mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 18:51:13 +08:00
899 lines
35 KiB
Rust
899 lines
35 KiB
Rust
//! dispatch 主循环:逐指令解码与 OpCode 臂分派、执行期 GC 安全点、
|
||
//! 步数/分配上限采样与二元运算宏 `binary_arith!`。
|
||
|
||
use std::io::Write;
|
||
|
||
use num_traits::Zero;
|
||
use oxide_bytecode::opcode::{self, OpCode};
|
||
use oxide_runtime_api as coercion;
|
||
use oxide_types::value::JsValue;
|
||
|
||
use super::Vm;
|
||
use crate::{vm_error, vm_trace, vm_warn};
|
||
|
||
macro_rules! binary_arith {
|
||
($self:ident, $a:expr, $b:expr, $rd:expr, $op:tt, $check_zero:expr) => {{
|
||
let lv = $self.regs[$a];
|
||
let rv = $self.regs[$b];
|
||
if lv.is_int() && rv.is_int() {
|
||
$self.regs[$rd] = JsValue::float(lv.as_int() as f64 $op rv.as_int() as f64);
|
||
} else if lv.is_bigint() && rv.is_bigint() {
|
||
let l = $self.bigint_value(lv).clone();
|
||
let r = $self.bigint_value(rv).clone();
|
||
if r.is_zero() && $check_zero {
|
||
// 仅除/模对 BigInt 零除数抛 RangeError;SUB/MUL 等其余二元运算
|
||
// 遇到 0n 必须正常计算(Number 路径走 f64 inf/NaN)。
|
||
$self.raise_error_kind("RangeError", "Division by zero")?;
|
||
$self.regs[$rd] = JsValue::undefined();
|
||
} else {
|
||
$self.regs[$rd] = $self.new_bigint(l $op r);
|
||
}
|
||
} else {
|
||
// 注意:混合 BigInt/Number 检查不能在此前置(对象操作数如
|
||
// `{valueOf: () => 2n}` 需先 ToPrimitive 再判定),统一放 coerce 之后。
|
||
let l = $self.coerce_primitive_bounded(lv, false)?;
|
||
let r = $self.coerce_primitive_bounded(rv, false)?;
|
||
if l.is_symbol() || r.is_symbol() {
|
||
// ToNumber(Symbol) 抛 TypeError(ECMA-262 §7.1.4),先于 BigInt 混合判定。
|
||
$self.raise_type_error("Cannot convert a Symbol value to a number")?;
|
||
$self.regs[$rd] = JsValue::undefined();
|
||
} else if l.is_bigint() && r.is_bigint() {
|
||
// 包装对象 coerce 后暴露双 BigInt(如 Object(2n) / 2n)。
|
||
let lv = $self.bigint_value(l).clone();
|
||
let rv = $self.bigint_value(r).clone();
|
||
if rv.is_zero() && $check_zero {
|
||
$self.raise_error_kind("RangeError", "Division by zero")?;
|
||
$self.regs[$rd] = JsValue::undefined();
|
||
} else {
|
||
$self.regs[$rd] = $self.new_bigint(lv $op rv);
|
||
}
|
||
} else if l.is_bigint() != r.is_bigint() {
|
||
// 包装对象 coerce 后暴露 BigInt 混合(如 Object(1n) - 1)。
|
||
$self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions")?;
|
||
$self.regs[$rd] = JsValue::undefined();
|
||
} else {
|
||
let ln = coercion::to_number(l);
|
||
let rn = coercion::to_number(r);
|
||
$self.regs[$rd] = JsValue::float(ln $op rn);
|
||
}
|
||
}
|
||
}}
|
||
}
|
||
|
||
impl Vm {
|
||
/// 主 dispatch 循环:逐指令解码并分派到各 `dispatch_*` 处理器,直到返回、
|
||
/// 异常逃出或触发步数/分配上限。
|
||
///
|
||
/// # 约定
|
||
/// - 完成值:HALT 与 RETURN 类指令把结果写回寄存器(顶层承载于 `regs[0]`),
|
||
/// 循环以 `Ok(value)` 返回。
|
||
/// - 异常:可捕获异常经 `unwind` 改写 pc/寄存器后就地继续;无 handler 时
|
||
/// 返回 `Err`,异常值由 `last_uncaught_value` 上交调用方。
|
||
/// - 寄存器镜像槽允许裸读:热点路径直接索引 `self.regs` 取模块 builtin 名集
|
||
/// 槽,槽值仅在 run/帧入口重载,进入循环前须保证已重载。
|
||
///
|
||
/// # 步骤
|
||
/// 1. 循环前缓存 `max_steps`/`max_alloc_bytes`,嵌套重入按 hop 计数兜底采样。
|
||
/// 2. 指令边界采执行期 GC 安全点(仅顶层 `native_call_depth == 0`)。
|
||
/// 3. 检查步数上限、单 run 分配上限与 pc 越界,超限按错误返回。
|
||
/// 4. 解码当前指令、递增 pc,按 OpCode 分派到处理器。
|
||
///
|
||
/// # 边界与前提
|
||
/// - 嵌套 dispatch(原生 builtin 重入执行 JS)不推进顶层 `steps`,靠重入
|
||
/// hop 计数每 64 跳强制一次轻采样兜底分配上限。
|
||
/// - `pc` 越过 `bytecode.len()` 视为内部错误,返回 `Err`(不抛 JS 异常)。
|
||
///
|
||
/// # 副作用
|
||
/// - 改写 `pc`、寄存器、帧栈与 GC 状态;可能触发字符串/两档 session 收集。
|
||
///
|
||
/// # 注意事项
|
||
/// - GC 安全点不得下移到嵌套 dispatch:调用方寄存器窗口副本存于 inline
|
||
/// 状态、非 GC 根,此时回收会把调用方 regs 中的活值当死值释放。
|
||
pub(crate) fn dispatch(&mut self) -> Result<JsValue, String> {
|
||
// config.max_steps / max_alloc_bytes 逐指令只读且循环内不变:提到循环外,
|
||
// 免每次经 kernel_core Arc 指针追寻读取(热点内仅有的 config 访问)。
|
||
let max_steps = self.kernel_core.config.max_steps;
|
||
let max_alloc_bytes = self.kernel_core.config.max_alloc_bytes;
|
||
let mut steps: u64 = 0;
|
||
// 小重入泵送盲区:native 终端循环泵送短 JS 重入时,顶层 steps 不推进、
|
||
// 每次重入 dispatch 太短到不了循环内 64 指令采样点,分配上限结构性永不
|
||
// 采样。重入边界按 hop 计数,每 64 跳强制一次顶层轻采样兜底。
|
||
if self.native_call_depth > 0 {
|
||
self.reentry_hops += 1;
|
||
if self.reentry_hops & 0x3F == 0 {
|
||
if let Some(cap) = max_alloc_bytes {
|
||
let used = self.run_alloc_bytes();
|
||
if used > cap {
|
||
vm_warn!(
|
||
"dispatch: memory limit {cap} exceeded at reentry hop {} (used {used}) at pc={}",
|
||
self.reentry_hops,
|
||
self.pc
|
||
);
|
||
return Err(format!("VM memory limit {cap} exceeded (used {used}) at pc={}", self.pc));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
loop {
|
||
steps += 1;
|
||
// 执行期 GC 安全点:仅在顶层 dispatch(native_call_depth == 0)
|
||
// 的指令边界触发——嵌套 dispatch(builtin 经 call_function_sync 重入
|
||
// 执行 JS 回调、generator/async 恢复)期间,调用方寄存器窗口副本存于
|
||
// inline 状态(非 GC 根),此时回收会把调用方 regs 中的活值当死值释放。
|
||
// 返回顶层后检查恢复,存活值此时已回拷为执行根。账目未超水位时仅
|
||
// 少量字段比较。
|
||
if self.native_call_depth == 0 {
|
||
// 宿主 `$262.gc()` 置位的强制收集在此边界消费:完整收集
|
||
// 唯一安全点(无在途 dispatch 局部值),与正常触发路径同一入口。
|
||
if self.gc_state.pending_forced_collect {
|
||
self.gc_state.pending_forced_collect = false;
|
||
self.collect_session_gc();
|
||
}
|
||
// 峰值高水位:同一边界采样 session 堆账目上界
|
||
let bytes = self.gc_state.session_bytes_allocated;
|
||
if bytes > self.gc_state.session_bytes_peak {
|
||
self.gc_state.session_bytes_peak = bytes;
|
||
}
|
||
// 单 run 分配包络高水位:O(1) 读(手工账目 + BigInt/cell 表长)。
|
||
let alloc = self.run_alloc_bytes();
|
||
if alloc > self.gc_state.run_alloc_peak {
|
||
self.gc_state.run_alloc_peak = alloc;
|
||
}
|
||
if bytes >= self.gc_state.string_gc_watermark {
|
||
self.maybe_collect_session_strings();
|
||
}
|
||
// 执行期原地 sweep 收集:O(1) 包络超触发水位 → 收集(无门控:
|
||
// 迭代器键引用经根收集标活,原地释放不搬移存活对象;
|
||
// 边界契约见 maybe_collect_in_run)。
|
||
if alloc >= self.gc_state.gc_watermark {
|
||
self.maybe_collect_in_run();
|
||
}
|
||
}
|
||
if let Some(max_steps) = max_steps {
|
||
if steps > max_steps {
|
||
vm_warn!("dispatch: step limit {} exceeded at pc={}", max_steps, self.pc);
|
||
self.profiling.set_instruction_count(steps);
|
||
return Err(format!("VM step limit exceeded at pc={}", self.pc));
|
||
}
|
||
}
|
||
// 单 run 分配上限:账目盲区(属性区扩容)靠两层采样兜住——轻层每
|
||
// 64 指令读三个计数器,深层每 2^18 指令全量重算(含逐对象属性区
|
||
// 重算);超限 run 按步数超限同款处理(默认 skip / --no-skip 下
|
||
// fail),防单测试 arena 高水位拖垮宿主。
|
||
if let Some(cap) = max_alloc_bytes {
|
||
let deep = (steps & 0x3FFFF) == 0;
|
||
if deep || (steps & 0x3F) == 0 {
|
||
let used = if deep { self.run_alloc_bytes_full() as usize } else { self.run_alloc_bytes() };
|
||
if used > cap {
|
||
vm_warn!("dispatch: memory limit {cap} exceeded (used {used}) at pc={}", self.pc);
|
||
self.profiling.set_instruction_count(steps);
|
||
return Err(format!("VM memory limit {cap} exceeded (used {used}) at pc={}", self.pc));
|
||
}
|
||
}
|
||
}
|
||
if self.pc >= self.bytecode.len() {
|
||
let tail: Vec<String> = self
|
||
.bytecode
|
||
.iter()
|
||
.enumerate()
|
||
.rev()
|
||
.take(5)
|
||
.map(|(i, &instr)| format!("{i}:{:?}", opcode::opcode(instr)))
|
||
.collect();
|
||
let fn_names: Vec<String> = self
|
||
.frames
|
||
.iter()
|
||
.map(|f| {
|
||
self.kernel_core
|
||
.perm_interner()
|
||
.lookup(f.function_name)
|
||
.map(|s| s.to_string())
|
||
.unwrap_or_else(|| "?".into())
|
||
})
|
||
.collect();
|
||
vm_error!(
|
||
"dispatch: program counter out of bounds pc={} len={} frames={} cell_stack={} tail={:?} fns={:?}",
|
||
self.pc,
|
||
self.bytecode.len(),
|
||
self.frames.len(),
|
||
self.cell_stack.len(),
|
||
tail,
|
||
fn_names
|
||
);
|
||
vm_error!("dispatch: program counter out of bounds pc={} len={}", self.pc, self.bytecode.len());
|
||
self.profiling.instruction_count = steps;
|
||
return Err("program counter out of bounds".into());
|
||
}
|
||
|
||
let pc = self.pc;
|
||
let instr = self.bytecode[pc];
|
||
let op = opcode::opcode(instr);
|
||
let rd = opcode::rd(instr) as usize;
|
||
let a = opcode::a(instr) as usize;
|
||
let b = opcode::b(instr) as usize;
|
||
self.pc = pc + 1;
|
||
|
||
// 逐指令 trace:运行时开关短路(默认关闭,零输出零分配);
|
||
// pc 为字节码 word 序号,与反汇编 offset 列同单位。
|
||
if self.trace_instructions {
|
||
eprintln!("pc={pc:4} {op:>16} rd={rd} a={a} b={b}");
|
||
}
|
||
|
||
// last-pc 现场:开启时每 2^16 指令追加写一行 pc/opcode/flat_id/frames,
|
||
// 供监督者超时/崩溃杀子进程后读回挂死点(精度 = 距挂死点 2^16 指令内);
|
||
// 关闭时零输出零分配。
|
||
if let Some(watch) = self.pc_watch.as_ref() {
|
||
if (steps & 0xFFFF) == 0 {
|
||
let line =
|
||
format!("pc={pc} op={op} flat_id={} frames={}\n", self.active_flat_id, self.frames.len());
|
||
let _ = std::fs::OpenOptions::new()
|
||
.create(true)
|
||
.append(true)
|
||
.open(watch)
|
||
.and_then(|mut f| f.write_all(line.as_bytes()));
|
||
}
|
||
}
|
||
|
||
match op {
|
||
OpCode::NOP => {}
|
||
|
||
OpCode::HALT => {
|
||
vm_trace!("HALT: regs[0]={:?}", self.regs[0]);
|
||
self.profiling.set_instruction_count(steps);
|
||
return Ok(self.regs[0]);
|
||
}
|
||
|
||
OpCode::LOAD_CONST => {
|
||
self.dispatch_load_const(rd, instr)?;
|
||
}
|
||
|
||
OpCode::LOAD_GLOBAL => match self.dispatch_load_global(rd, instr) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::LOAD_GLOBAL_TYPEOF => {
|
||
self.dispatch_load_global_typeof(rd, instr)?;
|
||
}
|
||
|
||
OpCode::CREATE_CLOSURE => {
|
||
self.dispatch_create_closure(rd, instr)?;
|
||
}
|
||
OpCode::MAKE_CELL => {
|
||
self.dispatch_make_cell(rd, instr)?;
|
||
}
|
||
OpCode::MAKE_CELL_FRESH => {
|
||
self.dispatch_make_cell_fresh(rd, instr)?;
|
||
}
|
||
OpCode::CELL_GET => {
|
||
self.dispatch_cell_get(rd, a, b)?;
|
||
}
|
||
OpCode::CELL_SET => {
|
||
self.dispatch_cell_set(a, b)?;
|
||
}
|
||
OpCode::LOAD_UPVALUE => {
|
||
self.dispatch_load_upvalue(rd, instr)?;
|
||
}
|
||
OpCode::STORE_UPVALUE => {
|
||
self.dispatch_store_upvalue(rd, a, b)?;
|
||
}
|
||
OpCode::CREATE_REGEXP => match self.dispatch_create_regexp(rd, a, b) {
|
||
Ok(Some(result)) => return Ok(result),
|
||
Ok(None) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::ADD => {
|
||
self.dispatch_add(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::CONCAT_N => {
|
||
self.dispatch_concat_n(rd, a)?;
|
||
}
|
||
|
||
OpCode::SUB => {
|
||
binary_arith!(self, a, b, rd, -, false);
|
||
}
|
||
|
||
OpCode::MUL => {
|
||
binary_arith!(self, a, b, rd, *, false);
|
||
}
|
||
|
||
OpCode::DIV => {
|
||
binary_arith!(self, a, b, rd, /, true);
|
||
}
|
||
|
||
OpCode::MOD => {
|
||
binary_arith!(self, a, b, rd, %, true);
|
||
}
|
||
|
||
OpCode::EXP => {
|
||
self.dispatch_exp(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::NEG => {
|
||
self.dispatch_neg(rd, a)?;
|
||
}
|
||
|
||
OpCode::BIT_AND => {
|
||
self.dispatch_bit_and(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::BIT_OR => {
|
||
self.dispatch_bit_or(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::BIT_XOR => {
|
||
self.dispatch_bit_xor(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::SHL => {
|
||
self.dispatch_shl(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::SHR => {
|
||
self.dispatch_shr(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::USHR => {
|
||
self.dispatch_ushr(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::BIT_NOT => {
|
||
self.dispatch_bit_not(rd, a)?;
|
||
}
|
||
|
||
OpCode::EQ => {
|
||
self.dispatch_eq(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::NEQ => {
|
||
self.dispatch_neq(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::LT => {
|
||
self.dispatch_lt(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::GT => {
|
||
self.dispatch_gt(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::LTE => {
|
||
self.dispatch_lte(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::GTE => {
|
||
self.dispatch_gte(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::STRICT_EQ => {
|
||
self.dispatch_strict_eq(rd, a, b);
|
||
}
|
||
|
||
OpCode::STRICT_NEQ => {
|
||
self.dispatch_strict_neq(rd, a, b);
|
||
}
|
||
|
||
OpCode::UNARY_PLUS => {
|
||
self.dispatch_unary_plus(rd, a)?;
|
||
}
|
||
|
||
OpCode::JMP => {
|
||
self.dispatch_jmp(instr);
|
||
}
|
||
|
||
OpCode::BREAK => {
|
||
self.dispatch_break(instr)?;
|
||
// 逃出 for-await-of 的异步关闭可能经 await 挂起(return() 的
|
||
// promise),挂起时须像 AWAIT 一样让内嵌 dispatch 返回,由恢复方
|
||
// 快照状态。
|
||
if self.async_suspended || self.async_gen_suspended {
|
||
self.profiling.set_instruction_count(steps);
|
||
return Ok(JsValue::undefined());
|
||
}
|
||
}
|
||
|
||
OpCode::CONTINUE => {
|
||
self.dispatch_continue(instr)?;
|
||
if self.async_suspended || self.async_gen_suspended {
|
||
self.profiling.set_instruction_count(steps);
|
||
return Ok(JsValue::undefined());
|
||
}
|
||
}
|
||
|
||
OpCode::JMP_IF_FALSE => {
|
||
self.dispatch_jmp_if_false(rd, instr);
|
||
}
|
||
|
||
OpCode::JMP_IF_TRUE => {
|
||
self.dispatch_jmp_if_true(rd, instr);
|
||
}
|
||
|
||
OpCode::JMP_IF_NULLISH => {
|
||
self.dispatch_jmp_if_nullish(rd, instr);
|
||
}
|
||
|
||
OpCode::LOAD_VAR => match self.dispatch_load_var(rd, a) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::STORE_VAR => match self.dispatch_store_var(rd, a, b) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::MOV => {
|
||
vm_trace!("MOV r{} = r{}", rd, a);
|
||
self.regs[rd] = self.regs[a];
|
||
}
|
||
|
||
OpCode::SPILL => {
|
||
self.dispatch_spill(rd)?;
|
||
}
|
||
|
||
OpCode::UNSPILL => {
|
||
self.dispatch_unspill(rd)?;
|
||
}
|
||
|
||
OpCode::CALL => match self.dispatch_call(rd, a, b) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::CALL_NATIVE => {
|
||
self.dispatch_call_native(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::CALL_SPREAD => match self.dispatch_call_spread(rd, a, b) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::NEW_EXPRESSION => match self.dispatch_new_expression(rd, a, b) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::NEW_EXPRESSION_SPREAD => match self.dispatch_new_expression_spread(rd, a, b) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::SUPER_CALL => match self.dispatch_super_call(rd, a) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::SUPER_CALL_SPREAD => match self.dispatch_super_call_spread(rd, a) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::SUPER_GET_PROP | OpCode::SUPER_STATIC_GET_PROP => {
|
||
match self.dispatch_super_get_prop(rd, a, b) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
}
|
||
}
|
||
|
||
OpCode::SET_HOME_OBJECT => match self.dispatch_set_home_object(rd, a) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::DEFINE_ACCESSOR => {
|
||
self.dispatch_define_accessor(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::DEFINE_ACCESSOR_DYNAMIC => {
|
||
self.dispatch_define_accessor_dynamic(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::DEFINE_PROP => {
|
||
self.dispatch_define_prop(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::DEFINE_GLOBAL_PROP => {
|
||
self.dispatch_define_global_prop(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::DEFINE_GLOBAL_PROP_C => {
|
||
let key_idx = self.bytecode[self.pc] as u16;
|
||
self.pc += 1;
|
||
self.dispatch_define_global_prop_c(a, key_idx)?;
|
||
}
|
||
|
||
OpCode::DEFINE_GLOBAL_PROP_IF_ABSENT => {
|
||
self.dispatch_define_global_prop_if_absent(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::DEFINE_GLOBAL_PROP_C_IF_ABSENT => {
|
||
let key_idx = self.bytecode[self.pc] as u16;
|
||
self.pc += 1;
|
||
self.dispatch_define_global_prop_c_if_absent(a, key_idx)?;
|
||
}
|
||
|
||
OpCode::DELETE_GLOBAL_PROP_C => {
|
||
let key_idx = self.bytecode[self.pc] as u16;
|
||
self.pc += 1;
|
||
self.dispatch_delete_global_prop_c(rd, a, key_idx)?;
|
||
}
|
||
|
||
OpCode::CAN_DECLARE_GLOBAL_FUNC => {
|
||
self.dispatch_can_declare_global_func(rd, b)?;
|
||
}
|
||
|
||
OpCode::DEFINE_GLOBAL_FUNC_BIND => {
|
||
self.dispatch_define_global_func_bind(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::DEFINE_PROP_ATTRS => {
|
||
let attrs = self.bytecode[self.pc] as u8;
|
||
self.pc += 1;
|
||
self.dispatch_define_prop_attrs(rd, a, b, attrs)?;
|
||
}
|
||
|
||
OpCode::DEFINE_ACCESSOR_ATTRS => {
|
||
let key_word = self.bytecode[self.pc];
|
||
let attrs = self.bytecode[self.pc + 1] as u8;
|
||
self.pc += 2;
|
||
self.dispatch_define_accessor_attrs(rd, a, b, key_word, attrs)?;
|
||
}
|
||
|
||
OpCode::DEFINE_ACCESSOR_ATTRS_DYNAMIC => {
|
||
let key_word = self.bytecode[self.pc];
|
||
let attrs = self.bytecode[self.pc + 1] as u8;
|
||
self.pc += 2;
|
||
self.dispatch_define_accessor_attrs_dynamic(rd, a, b, key_word, attrs)?;
|
||
}
|
||
|
||
OpCode::RETURN => match self.dispatch_return(instr) {
|
||
Ok(Some(result)) => return Ok(result),
|
||
Ok(None) => {
|
||
// 逃出 for-await-of 的异步关闭可能经 await 挂起(return() 的
|
||
// promise),挂起时须像 AWAIT 一样让内嵌 dispatch 返回,由恢复
|
||
// 方快照状态。
|
||
if self.async_suspended || self.async_gen_suspended {
|
||
self.profiling.set_instruction_count(steps);
|
||
return Ok(JsValue::undefined());
|
||
}
|
||
}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::IC_GET_PROP
|
||
| OpCode::IC_SET_PROP
|
||
| OpCode::GET_PROP
|
||
| OpCode::SET_PROP
|
||
| OpCode::SET_PROP_BATCH
|
||
| OpCode::GET_PROP_DYNAMIC
|
||
| OpCode::SET_PROP_DYNAMIC
|
||
| OpCode::SET_ELEM
|
||
| OpCode::GET_PRIVATE
|
||
| OpCode::SET_PRIVATE
|
||
| OpCode::INIT_PRIVATE
|
||
| OpCode::PRIVATE_BRAND_IN => {
|
||
self.dispatch_property_op(op, rd, a, b)?;
|
||
}
|
||
|
||
OpCode::NEW_OBJECT => {
|
||
self.dispatch_new_object(rd, instr)?;
|
||
}
|
||
|
||
OpCode::NEW_SESSION_OBJECT => {
|
||
self.dispatch_new_session_object(rd)?;
|
||
}
|
||
|
||
OpCode::CREATE_ARGUMENTS => {
|
||
self.dispatch_create_arguments(rd)?;
|
||
}
|
||
|
||
OpCode::CREATE_REST_ARRAY => {
|
||
let fixed_count = opcode::b(instr) as usize;
|
||
self.dispatch_create_rest_array(rd, fixed_count)?;
|
||
}
|
||
|
||
OpCode::NEW_ARRAY => {
|
||
self.dispatch_new_array(rd, instr);
|
||
}
|
||
|
||
OpCode::COMPOUND_ADD => {
|
||
self.dispatch_compound_add(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_SUB => {
|
||
self.dispatch_compound_sub(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_MUL => {
|
||
self.dispatch_compound_mul(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_DIV => {
|
||
self.dispatch_compound_div(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_MOD => {
|
||
self.dispatch_compound_mod(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_EXP => {
|
||
self.dispatch_compound_exp(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_AND => {
|
||
self.dispatch_compound_bit_and(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_OR => {
|
||
self.dispatch_compound_bit_or(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_XOR => {
|
||
self.dispatch_compound_bit_xor(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_SHL => {
|
||
self.dispatch_compound_shl(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_SHR => {
|
||
self.dispatch_compound_shr(rd, a)?;
|
||
}
|
||
|
||
OpCode::COMPOUND_USHR => {
|
||
self.dispatch_compound_ushr(rd, a)?;
|
||
}
|
||
|
||
OpCode::TYPEOF => {
|
||
self.dispatch_typeof(rd, a);
|
||
}
|
||
|
||
OpCode::TO_OBJECT => {
|
||
self.dispatch_to_object(rd)?;
|
||
}
|
||
|
||
OpCode::VOID => {
|
||
self.dispatch_void(rd);
|
||
}
|
||
|
||
OpCode::TEMPLATE_STR => {
|
||
self.dispatch_template_str(rd)?;
|
||
}
|
||
|
||
OpCode::GET_TEMPLATE_OBJECT => {
|
||
self.dispatch_get_template_object(rd)?;
|
||
}
|
||
|
||
OpCode::DELETE_PROP_STATIC => match self.dispatch_delete_prop_static(rd) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::DELETE_PROP_DYNAMIC => match self.dispatch_delete_prop_dynamic(rd, b) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::INSTANCEOF => {
|
||
self.dispatch_instanceof(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::IN => {
|
||
self.dispatch_in(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::NOT => {
|
||
self.dispatch_not(rd, a);
|
||
}
|
||
|
||
OpCode::AND => {
|
||
self.dispatch_and(rd, a, b);
|
||
}
|
||
|
||
OpCode::OR => {
|
||
self.dispatch_or(rd, a, b);
|
||
}
|
||
|
||
OpCode::NULLISH => {
|
||
self.dispatch_nullish(rd, a, b);
|
||
}
|
||
|
||
OpCode::INC_PRE => {
|
||
self.dispatch_inc_pre(rd, a)?;
|
||
}
|
||
|
||
OpCode::INC_POST => {
|
||
self.dispatch_inc_post(rd, a)?;
|
||
}
|
||
|
||
OpCode::DEC_PRE => {
|
||
self.dispatch_dec_pre(rd, a)?;
|
||
}
|
||
|
||
OpCode::DEC_POST => {
|
||
self.dispatch_dec_post(rd, a)?;
|
||
}
|
||
|
||
OpCode::MEMBER_INC
|
||
| OpCode::MEMBER_DEC
|
||
| OpCode::DYN_MEMBER_INC
|
||
| OpCode::DYN_MEMBER_DEC
|
||
| OpCode::COMPOUND_MEMBER_ADD
|
||
| OpCode::COMPOUND_MEMBER_SUB
|
||
| OpCode::COMPOUND_MEMBER_MUL
|
||
| OpCode::COMPOUND_MEMBER_DIV
|
||
| OpCode::COMPOUND_MEMBER_MOD
|
||
| OpCode::COMPOUND_MEMBER_EXP
|
||
| OpCode::COMPOUND_MEMBER_BIT_AND
|
||
| OpCode::COMPOUND_MEMBER_BIT_OR
|
||
| OpCode::COMPOUND_MEMBER_BIT_XOR
|
||
| OpCode::COMPOUND_MEMBER_SHL
|
||
| OpCode::COMPOUND_MEMBER_SHR
|
||
| OpCode::COMPOUND_MEMBER_USHR => {
|
||
self.dispatch_member_op(op, rd, a, b)?;
|
||
}
|
||
|
||
OpCode::FOR_IN_INIT => {
|
||
self.dispatch_for_in_init(a)?;
|
||
}
|
||
|
||
OpCode::FOR_IN_NEXT => {
|
||
self.dispatch_for_in_next(rd)?;
|
||
}
|
||
|
||
OpCode::FOR_IN_DONE => {
|
||
self.dispatch_for_in_done(rd);
|
||
}
|
||
|
||
OpCode::FOR_IN_CLEANUP => {
|
||
self.dispatch_for_in_cleanup();
|
||
}
|
||
|
||
OpCode::FOR_OF_INIT => {
|
||
self.dispatch_for_of_init(a)?;
|
||
}
|
||
|
||
OpCode::FOR_OF_NEXT => {
|
||
self.dispatch_for_of_next(rd)?;
|
||
}
|
||
|
||
OpCode::FOR_OF_DONE => {
|
||
self.dispatch_for_of_done(rd)?;
|
||
}
|
||
|
||
OpCode::FOR_OF_CLOSE => {
|
||
self.dispatch_for_of_close()?;
|
||
}
|
||
|
||
OpCode::FOR_AWAIT_OF_INIT => {
|
||
self.dispatch_for_await_of_init(a)?;
|
||
}
|
||
|
||
OpCode::FOR_AWAIT_OF_NEXT => {
|
||
self.dispatch_for_await_of_next(rd)?;
|
||
}
|
||
|
||
OpCode::FOR_AWAIT_OF_DONE => {
|
||
self.dispatch_for_await_of_done(rd, a)?;
|
||
}
|
||
|
||
OpCode::FOR_AWAIT_OF_CLOSE => {
|
||
self.dispatch_for_await_of_close()?;
|
||
// 异步 IteratorClose 可能经 await 挂起(return() 的 promise),
|
||
// 挂起时须像 AWAIT 一样让内嵌 dispatch 返回,由恢复方快照状态。
|
||
if self.async_suspended || self.async_gen_suspended {
|
||
self.profiling.set_instruction_count(steps);
|
||
return Ok(JsValue::undefined());
|
||
}
|
||
}
|
||
|
||
OpCode::REST_OBJECT => {
|
||
self.dispatch_rest_object(rd, a, b)?;
|
||
}
|
||
|
||
OpCode::SPREAD_OBJECT => {
|
||
self.dispatch_spread_object(rd, a)?;
|
||
}
|
||
|
||
OpCode::THROW => match self.dispatch_throw(rd) {
|
||
Ok(true) => continue,
|
||
Ok(false) => {}
|
||
Err(e) => return Err(e),
|
||
},
|
||
|
||
OpCode::TRY_BEGIN => {
|
||
self.dispatch_try_begin(instr);
|
||
}
|
||
|
||
OpCode::TRY_END => {
|
||
self.dispatch_try_end();
|
||
}
|
||
|
||
OpCode::TRY_FINALLY_BEGIN => {
|
||
self.dispatch_try_finally_begin(instr);
|
||
}
|
||
|
||
OpCode::TRY_FINALLY_ENTER => {
|
||
self.dispatch_try_finally_enter();
|
||
}
|
||
|
||
OpCode::TRY_FINALLY_END => match self.dispatch_try_finally_end() {
|
||
Ok(Some(result)) => return Ok(result),
|
||
Ok(None) => {
|
||
// 逃出 for-await-of 的异步关闭可能经 await 挂起(return() 的
|
||
// promise),挂起时须像 AWAIT 一样让内嵌 dispatch 返回,由恢复
|
||
// 方快照状态。
|
||
if self.async_suspended || self.async_gen_suspended {
|
||
self.profiling.set_instruction_count(steps);
|
||
return Ok(JsValue::undefined());
|
||
}
|
||
}
|
||
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::YIELD_STAR => {
|
||
// `yield*` 委托:取内层迭代器并推进一步。
|
||
// 未 done → 挂起让出(存委托迭代器);done → 委托完成值写 reg 0 继续外层;
|
||
// unwind 捕获到异常 → 继续 dispatch(已展开到 catch/finally);
|
||
// 异步委托 → 内层迭代已登记微任务队列,内嵌 dispatch 返回。
|
||
match self.dispatch_yield_star(rd)? {
|
||
crate::generator::YieldStarOutcome::Suspend(value) => {
|
||
self.generator_suspended = Some(value);
|
||
self.profiling.set_instruction_count(steps);
|
||
return Ok(JsValue::undefined());
|
||
}
|
||
crate::generator::YieldStarOutcome::Continue(value) => {
|
||
self.regs[0] = value;
|
||
}
|
||
crate::generator::YieldStarOutcome::Unwind => {}
|
||
crate::generator::YieldStarOutcome::AsyncSuspend => {
|
||
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());
|
||
}
|
||
}
|
||
|
||
OpCode::AWAIT => {
|
||
// 异步帧挂起:登记恢复反应后内嵌 dispatch 返回,恢复方快照挂起状态。
|
||
self.dispatch_await(rd)?;
|
||
self.profiling.set_instruction_count(steps);
|
||
return Ok(JsValue::undefined());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|