diff --git a/Cargo.lock b/Cargo.lock index 67d6851f..a15344ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.17.5" +version = "0.17.6" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.17.5" +version = "0.17.6" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.17.5" +version = "0.17.6" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.17.5" +version = "0.17.6" dependencies = [ "ansi_term", "bumpalo", @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.17.5" +version = "0.17.6" dependencies = [ "lru", "oxide_bytecode", @@ -1237,7 +1237,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.17.5" +version = "0.17.6" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1258,7 +1258,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.17.5" +version = "0.17.6" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1272,7 +1272,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.17.5" +version = "0.17.6" dependencies = [ "num-bigint", "oxc_allocator", @@ -1288,7 +1288,7 @@ dependencies = [ [[package]] name = "oxide_engine" -version = "0.17.5" +version = "0.17.6" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1300,7 +1300,7 @@ dependencies = [ [[package]] name = "oxide_fold" -version = "0.17.5" +version = "0.17.6" dependencies = [ "num-bigint", "oxide_bytecode", @@ -1312,7 +1312,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.17.5" +version = "0.17.6" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1321,7 +1321,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.17.5" +version = "0.17.6" dependencies = [ "bumpalo", "dashmap", @@ -1335,7 +1335,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.17.5" +version = "0.17.6" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1347,7 +1347,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.17.5" +version = "0.17.6" dependencies = [ "tracing", "tracing-appender", @@ -1356,11 +1356,11 @@ dependencies = [ [[package]] name = "oxide_net" -version = "0.17.5" +version = "0.17.6" [[package]] name = "oxide_parser" -version = "0.17.5" +version = "0.17.6" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1375,7 +1375,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.17.5" +version = "0.17.6" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1391,7 +1391,7 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.17.5" +version = "0.17.6" dependencies = [ "num-bigint", "num-traits", @@ -1404,7 +1404,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.17.5" +version = "0.17.6" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1424,7 +1424,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.17.5" +version = "0.17.6" dependencies = [ "bumpalo", "dashmap", @@ -1437,7 +1437,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.17.5" +version = "0.17.6" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 1e163b59..2d1e6498 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ members = [ ] [workspace.package] -version = "0.17.5" +version = "0.17.6" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_regalloc/src/rewrite.rs b/crates/oxide_regalloc/src/rewrite.rs index b3a4f6d0..78a17b40 100644 --- a/crates/oxide_regalloc/src/rewrite.rs +++ b/crates/oxide_regalloc/src/rewrite.rs @@ -90,7 +90,7 @@ pub(super) fn run(f: &mut IRFunction, map: &AllocMap) { } // 重写 inst 本体(含调用点参数连续性 MOV) - let (rewritten, arg_movs) = rewrite_inst(f, inst, map, &slot_color, i); + let (rewritten, arg_movs) = rewrite_inst(inst, map, &slot_color); // 发射顺序:UNSPILLs(按 vreg 升序)→ RMW UNSPILL → 连续性 MOVs → 指令 → SPILLs for &(vreg, color) in &use_unspills { @@ -133,9 +133,7 @@ pub(super) fn run(f: &mut IRFunction, map: &AllocMap) { } /// 重写单条指令:槽位映射 + 调用点参数连续性 MOV 补位。返回 (重写后指令, 参数 MOV 列表)。 -fn rewrite_inst( - f: &IRFunction, inst: &Inst, map: &AllocMap, slot_color: &BTreeMap, i: usize, -) -> (Inst, Vec<(u32, u32)>) { +fn rewrite_inst(inst: &Inst, map: &AllocMap, slot_color: &BTreeMap) -> (Inst, Vec<(u32, u32)>) { let raw_nargs = inst.ext.first().copied().unwrap_or(0); let nargs = raw_nargs; let first_arg = match inst.op { @@ -172,7 +170,6 @@ fn rewrite_inst( } } } - let _ = i; // 槽位重写 let rewrite = |o: Operand| -> Operand { @@ -275,7 +272,6 @@ fn rewrite_inst( _ => {} } } - let _ = f; // 防御:imm16 编码位的操作数必须是 Imm/None,不得是 Reg—— // 上面的 Reg 重写会改号,若该槽被改写,VM 侧按 imm16 读取会拿到错误值。 match inst.op { diff --git a/crates/oxide_vm/src/async_func.rs b/crates/oxide_vm/src/async_func.rs index 28cc233d..32b333df 100644 --- a/crates/oxide_vm/src/async_func.rs +++ b/crates/oxide_vm/src/async_func.rs @@ -70,6 +70,20 @@ pub(crate) const ASYNC_ESCAPE_PROMISE_PROP: &str = "__oxide_async_escape_promise /// 异步释放结算闭包上存释放方法 promise 的属性名(陈旧防御校验用)。 pub(crate) const ASYNC_DISPOSE_PROMISE_PROP: &str = "__oxide_async_dispose_promise__"; +/// 异步 dispatch 标志组:异步上下文、异步生成器上下文与三个 dispatch 标志 +/// (生成器 / 异步 / 异步生成器)。 +/// +/// 按值传递的 Copy 结构体,字段数五;保存点把整组 VM 标志合成一个结构体 +/// 字面量,恢复方整体接参,避免 4 至 5 个保存值散参搬运。 +#[derive(Clone, Copy)] +pub(crate) struct AsyncDispatchFlags { + pub(crate) ctx: Option, + pub(crate) gen_ctx: Option, + pub(crate) gd: bool, + pub(crate) ad: bool, + pub(crate) agd: bool, +} + impl Vm { /// 调用异步函数返回的 capability promise:创建上下文对象 + 状态盒,立即压帧 /// 同步执行 body 到第一个 AWAIT/RETURN/异常,返回 pending promise。 @@ -126,10 +140,13 @@ impl Vm { let state_ptr = self.async_state_ptr(ctx_val); let saved = self.save_inline_state(256); self.async_suspended = false; - let prev_ctx = self.async_context.take(); - let prev_dispatch = self.async_dispatch; - let prev_gen_ctx = self.async_gen_context.take(); - let prev_gen_dispatch = self.async_gen_dispatch; + let prev = AsyncDispatchFlags { + ctx: self.async_context.take(), + gen_ctx: self.async_gen_context.take(), + gd: self.generator_dispatch, + ad: self.async_dispatch, + agd: self.async_gen_dispatch, + }; self.async_dispatch = true; // 普通异步函数执行期间 AWAIT 走普通异步恢复路径:屏蔽外层异步生成器上下文。 self.async_gen_dispatch = false; @@ -142,7 +159,7 @@ impl Vm { let push_res = self.prepare_execution_initial(callee, this_value, &args); unsafe { (*state_ptr).args = args }; if let Err(e) = push_res { - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Err(e); @@ -150,7 +167,7 @@ impl Vm { unsafe { (*state_ptr).phase = AsyncPhase::Running }; let result = self.dispatch(); - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; if std::mem::take(&mut self.async_suspended) { @@ -189,10 +206,13 @@ impl Vm { let state_ptr = self.async_state_ptr(ctx_val); let saved = self.save_inline_state(256); self.async_suspended = false; - let prev_ctx = self.async_context.take(); - let prev_dispatch = self.async_dispatch; - let prev_gen_ctx = self.async_gen_context.take(); - let prev_gen_dispatch = self.async_gen_dispatch; + let prev = AsyncDispatchFlags { + ctx: self.async_context.take(), + gen_ctx: self.async_gen_context.take(), + gd: self.generator_dispatch, + ad: self.async_dispatch, + agd: self.async_gen_dispatch, + }; self.async_dispatch = true; // 普通异步函数执行期间 AWAIT 走普通异步恢复路径:屏蔽外层异步生成器上下文。 self.async_gen_dispatch = false; @@ -204,7 +224,7 @@ impl Vm { let restore_res = state.suspended.restore_into(self, state.callee); if restore_res.is_err() { // callee 记录的表代际已被回收(跨 run 且无存活函数引用),无法恢复。 - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Err("async function suspended across runs is no longer valid".into()); @@ -218,7 +238,7 @@ impl Vm { self.pending_error_kind = Some(self.thrown_error_kind(exc)); if self.unwind().is_err() { // 异常逃逸出异步帧(无 catch/finally):结算为 reject。 - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; let thrown = self.last_uncaught_value.take().unwrap_or(exc); self.finish_async(state_ptr, Err(thrown))?; @@ -230,7 +250,7 @@ impl Vm { } let result = self.dispatch(); - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; if std::mem::take(&mut self.async_suspended) { @@ -259,14 +279,14 @@ impl Vm { } /// 恢复嵌套 dispatch 覆盖的 async 上下文标志(含外层异步生成器上下文)。 - fn restore_async_flags( - &mut self, prev_ctx: Option, prev_dispatch: bool, prev_gen_ctx: Option, - prev_gen_dispatch: bool, - ) { - self.async_dispatch = prev_dispatch; - self.async_context = prev_ctx; - self.async_gen_dispatch = prev_gen_dispatch; - self.async_gen_context = prev_gen_ctx; + /// + /// 注意:`gd` 位(`generator_dispatch`)不写回——普通异步函数执行期间 + /// 生成器 dispatch 标志不被本路径覆盖,与保存点只存四字段同口径。 + fn restore_async_flags(&mut self, prev: AsyncDispatchFlags) { + self.async_dispatch = prev.ad; + self.async_context = prev.ctx; + self.async_gen_dispatch = prev.agd; + self.async_gen_context = prev.gen_ctx; } /// 结算异步函数:正常结束 resolve capability,异常结束 reject capability。 @@ -437,10 +457,13 @@ impl Vm { let saved = self.save_inline_state(256); // 清上一轮多层关闭残留的挂起信号(多层逐层结算每轮清零,防陈旧信号误消费)。 self.async_suspended = false; - let prev_ctx = self.async_context.take(); - let prev_dispatch = self.async_dispatch; - let prev_gen_ctx = self.async_gen_context.take(); - let prev_gen_dispatch = self.async_gen_dispatch; + let prev = AsyncDispatchFlags { + ctx: self.async_context.take(), + gen_ctx: self.async_gen_context.take(), + gd: self.generator_dispatch, + ad: self.async_dispatch, + agd: self.async_gen_dispatch, + }; self.async_dispatch = true; self.async_gen_dispatch = false; self.async_context = Some(ctx); @@ -454,14 +477,14 @@ impl Vm { Some(p) if p.close_promise == promise ); if is_stale { - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); } let restore_res = state.suspended.restore_into(self, state.callee); if restore_res.is_err() { - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Err("async function suspended across runs is no longer valid".into()); @@ -486,7 +509,7 @@ impl Vm { Ok(true) => { self.async_suspended = false; self.snapshot_async(unsafe { &mut *state_ptr })?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); @@ -504,7 +527,7 @@ impl Vm { if self.unwind().is_err() { let exc = self.last_uncaught_value.take().unwrap_or(value); self.finish_async(state_ptr, Err(exc))?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); @@ -513,7 +536,7 @@ impl Vm { // 处理器体内再挂起(await):快照新状态后退出。 if std::mem::take(&mut self.async_suspended) { self.snapshot_async(unsafe { &mut *state_ptr })?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); @@ -528,7 +551,7 @@ impl Vm { self.finish_async(state_ptr, Err(exc))?; } } - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); @@ -548,7 +571,7 @@ impl Vm { // 完成跳转后 body 继续执行到下一个 await/return/异常。 if std::mem::take(&mut self.async_suspended) { self.snapshot_async(unsafe { &mut *state_ptr })?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); @@ -565,7 +588,7 @@ impl Vm { } } } - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); Ok(()) @@ -574,13 +597,12 @@ impl Vm { /// 续 dispatch 并结算:运行 body 到下一个 AWAIT/RETURN/异常,挂起则快照新状态, /// 完成/异常则结算 capability。恢复调用方状态。 fn dispatch_and_finish_async( - &mut self, state_ptr: *mut AsyncState, saved: Box, prev_ctx: Option, - prev_dispatch: bool, prev_gen_ctx: Option, prev_gen_dispatch: bool, + &mut self, state_ptr: *mut AsyncState, saved: Box, prev: AsyncDispatchFlags, ) -> Result<(), String> { let result = self.dispatch(); if std::mem::take(&mut self.async_suspended) { self.snapshot_async(unsafe { &mut *state_ptr })?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); @@ -595,7 +617,7 @@ impl Vm { self.finish_async(state_ptr, Err(exc))?; } } - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); Ok(()) @@ -621,10 +643,13 @@ impl Vm { let saved = self.save_inline_state(256); // 清上一轮残留的挂起信号(防陈旧信号误消费)。 self.async_suspended = false; - let prev_ctx = self.async_context.take(); - let prev_dispatch = self.async_dispatch; - let prev_gen_ctx = self.async_gen_context.take(); - let prev_gen_dispatch = self.async_gen_dispatch; + let prev = AsyncDispatchFlags { + ctx: self.async_context.take(), + gen_ctx: self.async_gen_context.take(), + gd: self.generator_dispatch, + ad: self.async_dispatch, + agd: self.async_gen_dispatch, + }; self.async_dispatch = true; self.async_gen_dispatch = false; self.async_context = Some(ctx); @@ -638,14 +663,14 @@ impl Vm { Some(p) if p.dispose_promise == promise ); if is_stale { - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); } let restore_res = state.suspended.restore_into(self, state.callee); if restore_res.is_err() { - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Err("async function suspended across runs is no longer valid".into()); @@ -658,7 +683,7 @@ impl Vm { Some(p) => (p.mark, p.completion, p.kind), // 陈旧防御已早退,正常路径此处必为 Some;防御性兜底。 None => { - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); @@ -675,7 +700,7 @@ impl Vm { // 从水位续释放循环(复用批量释放核心);再挂起则重新登记 + 快照 + 返回。 if matches!(self.dispose_above_core(mark, kind, completion)?, DisposePhase::Suspended) { self.snapshot_async(unsafe { &mut *state_ptr })?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); @@ -688,19 +713,12 @@ impl Vm { if self.exception_value.is_some() && self.unwind().is_err() { let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined()); self.finish_async(state_ptr, Err(exc))?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); } - self.dispatch_and_finish_async( - state_ptr, - saved, - prev_ctx, - prev_dispatch, - prev_gen_ctx, - prev_gen_dispatch, - ) + self.dispatch_and_finish_async(state_ptr, saved, prev) } DisposeResumeKind::Unwind(handler) => { // 重压 handler 再入 unwind(handler 已弹出,不重压则 catch/finally 丢失)。 @@ -710,19 +728,12 @@ impl Vm { if self.unwind().is_err() { let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined()); self.finish_async(state_ptr, Err(exc))?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); } - self.dispatch_and_finish_async( - state_ptr, - saved, - prev_ctx, - prev_dispatch, - prev_gen_ctx, - prev_gen_dispatch, - ) + self.dispatch_and_finish_async(state_ptr, saved, prev) } DisposeResumeKind::Escape(completion_val) => { if self.exception_value.is_some() { @@ -730,19 +741,12 @@ impl Vm { if self.unwind().is_err() { let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined()); self.finish_async(state_ptr, Err(exc))?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); } - self.dispatch_and_finish_async( - state_ptr, - saved, - prev_ctx, - prev_dispatch, - prev_gen_ctx, - prev_gen_dispatch, - ) + self.dispatch_and_finish_async(state_ptr, saved, prev) } else { // 无合并错误:执行完成。 match completion_val { @@ -750,30 +754,16 @@ impl Vm { let result = self.do_return(ret_val)?; if let Some(result) = result { self.finish_async(state_ptr, Ok(result))?; - self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch); + self.restore_async_flags(prev); self.native_call_depth -= 1; self.restore_inline_state(saved); return Ok(()); } - self.dispatch_and_finish_async( - state_ptr, - saved, - prev_ctx, - prev_dispatch, - prev_gen_ctx, - prev_gen_dispatch, - ) + self.dispatch_and_finish_async(state_ptr, saved, prev) } Completion::Break { target_pc, .. } | Completion::Continue { target_pc, .. } => { self.pc = target_pc; - self.dispatch_and_finish_async( - state_ptr, - saved, - prev_ctx, - prev_dispatch, - prev_gen_ctx, - prev_gen_dispatch, - ) + self.dispatch_and_finish_async(state_ptr, saved, prev) } } } diff --git a/crates/oxide_vm/src/async_generator.rs b/crates/oxide_vm/src/async_generator.rs index f3a3c8bd..3994392b 100644 --- a/crates/oxide_vm/src/async_generator.rs +++ b/crates/oxide_vm/src/async_generator.rs @@ -20,6 +20,7 @@ use oxide_runtime_api::{NativeResult, VmHost}; use oxide_types::object::{Cell, JsObject, NativeFnPtr, PropAttributes}; use oxide_types::value::JsValue; +use crate::async_func::AsyncDispatchFlags; use crate::generator::{DelegateOutcome, GeneratorResumeMode}; use crate::vm::{Completion, DisposeResumeKind, Vm}; use crate::vm_dispatch_misc::DisposePhase; @@ -320,11 +321,13 @@ impl Vm { let saved = self.save_inline_state(256); self.generator_suspended = None; self.async_gen_suspended = false; - let prev_ctx = self.async_context.take(); - let prev_gd = self.generator_dispatch; - let prev_ad = self.async_dispatch; - let prev_gen_ctx = self.async_gen_context.take(); - let prev_agd = self.async_gen_dispatch; + let prev = AsyncDispatchFlags { + ctx: self.async_context.take(), + gen_ctx: self.async_gen_context.take(), + gd: self.generator_dispatch, + ad: self.async_dispatch, + agd: self.async_gen_dispatch, + }; self.generator_dispatch = true; self.async_dispatch = true; self.async_gen_dispatch = true; @@ -337,11 +340,11 @@ impl Vm { let restore_res = state.suspended.restore_into(self, state.callee); if restore_res.is_err() { // callee 记录的表代际已被回收(跨 run 且无存活函数引用),无法恢复。 - self.async_gen_dispatch = prev_agd; - self.async_gen_context = prev_gen_ctx; - self.generator_dispatch = prev_gd; - self.async_dispatch = prev_ad; - self.async_context = prev_ctx; + self.async_gen_dispatch = prev.agd; + self.async_gen_context = prev.gen_ctx; + self.generator_dispatch = prev.gd; + self.async_dispatch = prev.ad; + self.async_context = prev.ctx; self.native_call_depth -= 1; self.restore_inline_state(saved); return Err("async generator suspended across runs is no longer valid".into()); @@ -369,7 +372,7 @@ impl Vm { .last_uncaught_value .take() .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_exc(state_ptr, saved, gen_val, exc); } Ok(DelegateOutcome::Suspend { .. }) => { @@ -378,7 +381,7 @@ impl Vm { // dispatch 之前返回,调度标志须在此恢复(dispatch 后的恢复不会执行)。 unsafe { (*state_ptr).phase = AsyncGenPhase::AwaitSuspended }; self.snapshot_async_generator(state_ptr)?; - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.restore_inline_state(saved); return Ok(()); } @@ -390,7 +393,7 @@ impl Vm { // (return 请求值经 Await 步挂起结算),此臂仅作穷尽防御。 let completed = self.complete_generator_return(value); if let Some(completed) = completed? { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_ok(state_ptr, saved, gen_val, completed); } // 进入 finally 穿越:继续 dispatch。 @@ -415,14 +418,14 @@ impl Vm { self.pending_error_kind = Some(self.thrown_error_kind(exc)); if self.unwind().is_err() { let thrown = self.last_uncaught_value.take().unwrap_or(exc); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_exc(state_ptr, saved, gen_val, thrown); } } GeneratorResumeMode::Return(value) => { let completed = self.complete_generator_return(value); if let Some(completed) = completed? { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_ok(state_ptr, saved, gen_val, completed); } // 进入 finally 穿越:继续 dispatch。 @@ -432,7 +435,7 @@ impl Vm { } let result = self.dispatch(); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.post_dispatch_async_gen(state_ptr, saved, gen_val, result) } @@ -605,15 +608,12 @@ impl Vm { } /// 恢复嵌套 dispatch 覆盖的 VM 标志(dispatch 前提前返回的路径用)。 - fn restore_async_gen_flags( - &mut self, prev_ctx: Option, prev_gen_ctx: Option, prev_gd: bool, prev_ad: bool, - prev_agd: bool, - ) { - self.async_gen_dispatch = prev_agd; - self.async_gen_context = prev_gen_ctx; - self.generator_dispatch = prev_gd; - self.async_dispatch = prev_ad; - self.async_context = prev_ctx; + fn restore_async_gen_flags(&mut self, prev: AsyncDispatchFlags) { + self.async_gen_dispatch = prev.agd; + self.async_gen_context = prev.gen_ctx; + self.generator_dispatch = prev.gd; + self.async_dispatch = prev.ad; + self.async_context = prev.ctx; self.native_call_depth -= 1; } @@ -842,11 +842,13 @@ impl Vm { // 清上一轮多层关闭残留的挂起信号(多层逐层结算每轮清零,防陈旧信号误消费)。 self.generator_suspended = None; self.async_gen_suspended = false; - let prev_ctx = self.async_context.take(); - let prev_gd = self.generator_dispatch; - let prev_ad = self.async_dispatch; - let prev_gen_ctx = self.async_gen_context.take(); - let prev_agd = self.async_gen_dispatch; + let prev = AsyncDispatchFlags { + ctx: self.async_context.take(), + gen_ctx: self.async_gen_context.take(), + gd: self.generator_dispatch, + ad: self.async_dispatch, + agd: self.async_gen_dispatch, + }; self.generator_dispatch = true; self.async_dispatch = true; self.async_gen_dispatch = true; @@ -862,13 +864,13 @@ impl Vm { Some(p) if p.close_promise == promise ); if is_stale { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.restore_inline_state(saved); return Ok(()); } let restore_res = state.suspended.restore_into(self, state.callee); if restore_res.is_err() { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.restore_inline_state(saved); return Err("async generator suspended across runs is no longer valid".into()); } @@ -880,7 +882,7 @@ impl Vm { Some(p) => (p.completion, p.remaining), // 陈旧防御已早退,正常路径此处必为 Some;防御性兜底。 None => { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.restore_inline_state(saved); return Ok(()); } @@ -897,7 +899,7 @@ impl Vm { self.async_gen_suspended = false; unsafe { (*state_ptr).phase = AsyncGenPhase::AwaitSuspended }; self.snapshot_async_generator(state_ptr)?; - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.restore_inline_state(saved); return Ok(()); } @@ -913,11 +915,11 @@ impl Vm { self.pending_error_kind = Some(self.thrown_error_kind(value)); if self.unwind().is_err() { let exc = self.last_uncaught_value.take().unwrap_or(value); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_exc(state_ptr, saved, ctx, exc); } let result = self.dispatch(); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.post_dispatch_async_gen(state_ptr, saved, ctx, result); } @@ -926,18 +928,18 @@ impl Vm { Completion::Return { value: ret_val, .. } => { let result = self.do_return(ret_val)?; if let Some(result) = result { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_ok(state_ptr, saved, ctx, result); } // 嵌套帧未弹空:续 dispatch。 let result = self.dispatch(); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.post_dispatch_async_gen(state_ptr, saved, ctx, result) } Completion::Break { target_pc, .. } | Completion::Continue { target_pc, .. } => { self.pc = target_pc; let result = self.dispatch(); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.post_dispatch_async_gen(state_ptr, saved, ctx, result) } } @@ -964,11 +966,13 @@ impl Vm { // 清上一轮残留的挂起信号(防陈旧信号误消费)。 self.generator_suspended = None; self.async_gen_suspended = false; - let prev_ctx = self.async_context.take(); - let prev_gd = self.generator_dispatch; - let prev_ad = self.async_dispatch; - let prev_gen_ctx = self.async_gen_context.take(); - let prev_agd = self.async_gen_dispatch; + let prev = AsyncDispatchFlags { + ctx: self.async_context.take(), + gen_ctx: self.async_gen_context.take(), + gd: self.generator_dispatch, + ad: self.async_dispatch, + agd: self.async_gen_dispatch, + }; self.generator_dispatch = true; self.async_dispatch = true; self.async_gen_dispatch = true; @@ -984,13 +988,13 @@ impl Vm { Some(p) if p.dispose_promise == promise ); if is_stale { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.restore_inline_state(saved); return Ok(()); } let restore_res = state.suspended.restore_into(self, state.callee); if restore_res.is_err() { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.restore_inline_state(saved); return Err("async generator suspended across runs is no longer valid".into()); } @@ -1002,7 +1006,7 @@ impl Vm { Some(p) => (p.mark, p.completion, p.kind), // 陈旧防御已早退,正常路径此处必为 Some;防御性兜底。 None => { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.restore_inline_state(saved); return Ok(()); } @@ -1019,7 +1023,7 @@ impl Vm { if matches!(self.dispose_above_core(mark, kind, completion)?, DisposePhase::Suspended) { unsafe { (*state_ptr).phase = AsyncGenPhase::AwaitSuspended }; self.snapshot_async_generator(state_ptr)?; - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.restore_inline_state(saved); return Ok(()); } @@ -1030,11 +1034,11 @@ impl Vm { // 有合并错误则展开(无处理器则 reject 当前请求),否则续行。 if self.exception_value.is_some() && self.unwind().is_err() { let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined()); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_exc(state_ptr, saved, ctx, exc); } let result = self.dispatch(); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.post_dispatch_async_gen(state_ptr, saved, ctx, result) } DisposeResumeKind::Unwind(handler) => { @@ -1044,11 +1048,11 @@ impl Vm { } if self.unwind().is_err() { let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined()); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_exc(state_ptr, saved, ctx, exc); } let result = self.dispatch(); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.post_dispatch_async_gen(state_ptr, saved, ctx, result) } DisposeResumeKind::Escape(completion_val) => { @@ -1056,11 +1060,11 @@ impl Vm { // 有合并错误:丢弃完成值,展开到外围处理器(无处理器则 reject)。 if self.unwind().is_err() { let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined()); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_exc(state_ptr, saved, ctx, exc); } let result = self.dispatch(); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.post_dispatch_async_gen(state_ptr, saved, ctx, result) } else { // 无合并错误:执行完成。 @@ -1068,18 +1072,18 @@ impl Vm { Completion::Return { value: ret_val, .. } => { let result = self.do_return(ret_val)?; if let Some(result) = result { - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); return self.finish_async_gen_ok(state_ptr, saved, ctx, result); } // 嵌套帧未弹空:续 dispatch。 let result = self.dispatch(); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.post_dispatch_async_gen(state_ptr, saved, ctx, result) } Completion::Break { target_pc, .. } | Completion::Continue { target_pc, .. } => { self.pc = target_pc; let result = self.dispatch(); - self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); + self.restore_async_gen_flags(prev); self.post_dispatch_async_gen(state_ptr, saved, ctx, result) } } diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index 220f7431..6f4a9592 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -1,5 +1,6 @@ use crate::native::NativeFn; -use crate::vm::{native_fn_ptr_to_fn, FrameArgs, FrameContinuation, Vm}; +use crate::vm::{native_fn_ptr_to_fn, ConstructArgs, FrameArgs, FrameContinuation, Vm}; +use crate::vm_support::FunctionFlags; use crate::{vm_debug, vm_trace}; use oxide_builtins::iterator::make_iterator_for_value; use oxide_builtins::{builtins_debug, builtins_trace}; @@ -156,9 +157,7 @@ impl Vm { callee, this, FrameArgs::Slice(&args), - None, - None, - JsValue::undefined(), + ConstructArgs::none(), FrameContinuation::None, 0, ) @@ -197,10 +196,7 @@ impl Vm { let result = self.create_function_object( sub_idx, self.active_table_gen, - is_arrow, - is_class_constructor, - is_derived_constructor, - needs_home_object, + FunctionFlags::new(is_arrow, is_class_constructor, is_derived_constructor), ); // 箭头函数词法继承 super 上下文:home object 从外层函数(当前 callee) // 继承。类方法由 SET_HOME_OBJECT 显式挂接,不经此路径。 @@ -724,9 +720,7 @@ impl Vm { first: first_arg_reg, count: arg_count, }, - Some(254), - Some(derived_this), - new_target, + ConstructArgs::new(254, derived_this, new_target), FrameContinuation::None, call_window, )?; @@ -1026,9 +1020,7 @@ impl Vm { callee, this_value, FrameArgs::Slice(&args), - None, - None, - JsValue::undefined(), + ConstructArgs::none(), FrameContinuation::None, 0, )?; @@ -1175,9 +1167,7 @@ impl Vm { constructor, this_value, FrameArgs::Slice(&args), - Some(rd as u8), - Some(new_obj_val), - constructor, + ConstructArgs::new(rd as u8, new_obj_val, constructor), FrameContinuation::None, 0, )?; @@ -1285,9 +1275,7 @@ impl Vm { super_ctor, derived_this, FrameArgs::Slice(&args), - Some(254), - Some(derived_this), - new_target, + ConstructArgs::new(254, derived_this, new_target), FrameContinuation::None, 0, )?; diff --git a/crates/oxide_vm/src/dispatch/property.rs b/crates/oxide_vm/src/dispatch/property.rs index a789c1a1..0118a609 100644 --- a/crates/oxide_vm/src/dispatch/property.rs +++ b/crates/oxide_vm/src/dispatch/property.rs @@ -7,6 +7,7 @@ use oxide_types::value::JsValue; use crate::ic_helper::{self, ic_get_hit, ic_set_hit, VIRTUAL_LENGTH_SLOT}; use crate::vm::{Vm, MAX_PROTO_CHAIN_DEPTH}; +use crate::vm_props::SetContract; #[cold] fn prop_cache_miss() {} @@ -526,7 +527,14 @@ impl Vm { self.ordinary_set_dispatch(obj, prop_name_si, value, receiver, self.current_strict())?; return Ok(()); } - self.create_named_prop_fast(obj, prop_name_si, value, receiver, ic_pc, true, self.current_strict())?; + self.create_named_prop_fast( + obj, + prop_name_si, + value, + receiver, + ic_pc, + SetContract::dispatch(self.current_strict()), + )?; } Ok(()) diff --git a/crates/oxide_vm/src/promise/constructor.rs b/crates/oxide_vm/src/promise/constructor.rs index 0e4e8480..55f5eef9 100644 --- a/crates/oxide_vm/src/promise/constructor.rs +++ b/crates/oxide_vm/src/promise/constructor.rs @@ -9,7 +9,7 @@ use oxide_runtime_api::NativeResult; use oxide_types::object::{JsObject, NativeFnPtr, PropAttributes}; use oxide_types::value::JsValue; -use crate::vm::{FrameArgs, FrameContinuation, Vm}; +use crate::vm::{ConstructArgs, FrameArgs, FrameContinuation, Vm}; use super::aggregate::{ promise_static_all, promise_static_all_keyed, promise_static_all_settled, promise_static_all_settled_keyed, @@ -233,9 +233,7 @@ impl Vm { ctor, this_value, FrameArgs::Slice(args), - Some(0), - Some(new_obj_val), - new_target, + ConstructArgs::new(0, new_obj_val, new_target), FrameContinuation::None, 0, ) diff --git a/crates/oxide_vm/src/vm/call.rs b/crates/oxide_vm/src/vm/call.rs index 49df80d4..b33f74b0 100644 --- a/crates/oxide_vm/src/vm/call.rs +++ b/crates/oxide_vm/src/vm/call.rs @@ -12,6 +12,29 @@ use super::{native_fn_ptr_to_fn, Vm}; use crate::native::NativeFn; use crate::{vm_debug, vm_trace}; +/// 压帧构造三元组:构造结果寄存器、构造出的 this、new.target。 +/// +/// 按值传递的 Copy 结构体,字段数三;非构造调用方统一传 `none()`, +/// 构造调用方传 `new(...)` 三值,避免三元组散参样板。 +#[derive(Clone, Copy)] +pub(crate) struct ConstructArgs { + result_reg: Option, + constructed_this: Option, + new_target: JsValue, +} + +impl ConstructArgs { + /// 非构造调用:无结果寄存器、无构造 this,new.target 为 undefined。 + pub(crate) fn none() -> Self { + Self { result_reg: None, constructed_this: None, new_target: JsValue::undefined() } + } + + /// 构造调用:携带结果寄存器、构造 this 与 new.target。 + pub(crate) fn new(result_reg: u8, constructed_this: JsValue, new_target: JsValue) -> Self { + Self { result_reg: Some(result_reg), constructed_this: Some(constructed_this), new_target } + } +} + impl Vm { fn pack_sync_native_call_args(&mut self, receiver: JsValue, callee: JsValue, args: &[JsValue]) -> Vec { self.regs[253] = receiver; @@ -219,10 +242,14 @@ impl Vm { /// # 副作用 /// - 压入调用帧与各类保存栈,改写 pc / bytecode / 活动寄存器上限与镜像槽; /// `continuation` 决定返回后的续行方式。 - #[expect(clippy::too_many_arguments)] pub(crate) fn push_bytecode_frame( - &mut self, callee: JsValue, this_value: JsValue, args: FrameArgs, construct_result_reg: Option, - constructed_this: Option, new_target: JsValue, continuation: FrameContinuation, call_window: u8, + &mut self, + callee: JsValue, + this_value: JsValue, + args: FrameArgs, + construct: ConstructArgs, + continuation: FrameContinuation, + call_window: u8, ) -> Result<(), String> { vm_trace!( "push_bytecode_frame: depth={}, args={}, continuation={:?}", @@ -312,7 +339,7 @@ impl Vm { } else { oxide_runtime_api::to_object(this_value, self)? }; - self.regs[255] = new_target; + self.regs[255] = construct.new_target; self.saved_bytecode_stack.push(std::mem::take(&mut self.bytecode)); self.saved_immutables_stack.push(self.active_immutables); @@ -350,8 +377,8 @@ impl Vm { saved_new_target, callee, arguments_obj: JsValue::undefined(), - construct_result_reg, - constructed_this, + construct_result_reg: construct.result_reg, + constructed_this: construct.constructed_this, is_derived_constructor: obj.is_derived_constructor(), super_called: false, strict: sub_is_strict, @@ -382,6 +409,8 @@ mod tests { use oxide_runtime_api::VmHost; use oxide_types::object::NativeFnPtr; + use crate::vm_support::FunctionFlags; + fn native_return_last_arg(vm: &mut Vm, args: &[u8]) -> NativeResult { let reg = *args.last().expect("receiver + args"); NativeResult::Ok(vm.reg(reg)) @@ -510,7 +539,7 @@ mod tests { vm.active_reg_limit = 254; vm.regs[253] = JsValue::int(42); - let callee = vm.create_function_object(1, vm.current_gen, false, false, false, false); + let callee = vm.create_function_object(1, vm.current_gen, FunctionFlags::none()); let callee_obj = unsafe { &*callee.as_js_object_ptr() }; let result = vm .call_bytecode_function_inline(callee, callee_obj, JsValue::undefined(), &[]) @@ -534,7 +563,7 @@ mod tests { vm.regs[253] = JsValue::int(7); vm.regs[254] = JsValue::int(8); - let inner_callee = vm.create_function_object(1, vm.current_gen, false, false, false, false); + let inner_callee = vm.create_function_object(1, vm.current_gen, FunctionFlags::none()); let outer_native = native_function(&mut vm, native_nested_inline_254); let result = vm .call_function_sync(outer_native, JsValue::int(99), &[inner_callee]) @@ -563,14 +592,12 @@ mod tests { vm.regs[1] = JsValue::int(10); vm.regs[2] = JsValue::int(20); - let callee = vm.create_function_object(1, vm.current_gen, false, false, false, false); + let callee = vm.create_function_object(1, vm.current_gen, FunctionFlags::none()); vm.push_bytecode_frame( callee, JsValue::undefined(), super::FrameArgs::RegRange { first: 1, count: 2 }, - None, - None, - JsValue::undefined(), + ConstructArgs::none(), super::FrameContinuation::None, 0, ) diff --git a/crates/oxide_vm/src/vm/dynamic.rs b/crates/oxide_vm/src/vm/dynamic.rs index d1b5ae22..065e4c96 100644 --- a/crates/oxide_vm/src/vm/dynamic.rs +++ b/crates/oxide_vm/src/vm/dynamic.rs @@ -11,6 +11,7 @@ use oxide_types::object::PropAttributes; use oxide_types::value::JsValue; use super::Vm; +use crate::vm_support::FunctionFlags; /// 缺省 no-op 编译服务:两方法均返 `Err`(错误消息指向「未安装编译服务」)。 /// @@ -97,7 +98,7 @@ impl Vm { table.immutables.resize(table.modules.len(), OnceLock::new()); table.si_tables.resize(table.modules.len(), OnceLock::new()); - let func_val = self.create_function_object(base, self.current_gen, false, false, false, false); + let func_val = self.create_function_object(base, self.current_gen, FunctionFlags::none()); let func_obj = unsafe { &mut *func_val.as_js_object_ptr() }; let length_si = self.kernel_core.perm_interner().intern("length").0; let name_si = self.kernel_core.perm_interner().intern("name").0; @@ -156,7 +157,7 @@ impl Vm { // 平表变长后同步扩容常量缓存与 si 侧表,否则激活新模块常量时越界 panic。 table.immutables.resize(table.modules.len(), OnceLock::new()); table.si_tables.resize(table.modules.len(), OnceLock::new()); - Ok(self.create_function_object(base, self.current_gen, false, false, false, false)) + Ok(self.create_function_object(base, self.current_gen, FunctionFlags::none())) } /// 动态编译脚本(普通脚本模式):顶层 var/function 声明落全局对象 @@ -195,7 +196,7 @@ impl Vm { // 平表变长后同步扩容常量缓存与 si 侧表,否则激活新模块常量时越界 panic。 table.immutables.resize(table.modules.len(), OnceLock::new()); table.si_tables.resize(table.modules.len(), OnceLock::new()); - Ok(self.create_function_object(base, self.current_gen, false, false, false, false)) + Ok(self.create_function_object(base, self.current_gen, FunctionFlags::none())) } } diff --git a/crates/oxide_vm/src/vm/mod.rs b/crates/oxide_vm/src/vm/mod.rs index 2ca9b53f..2c975e06 100644 --- a/crates/oxide_vm/src/vm/mod.rs +++ b/crates/oxide_vm/src/vm/mod.rs @@ -37,6 +37,7 @@ mod props; mod tables; mod vmhost; +pub(crate) use call::ConstructArgs; pub(crate) use dynamic::NoopCompilerService; pub(crate) use frames::FrameArgs; pub use frames::{CallFrame, Completion, ForInIter, FrameContinuation, TryHandler}; diff --git a/crates/oxide_vm/src/vm_dispatch_ctrl.rs b/crates/oxide_vm/src/vm_dispatch_ctrl.rs index 683f0fe0..28270301 100644 --- a/crates/oxide_vm/src/vm_dispatch_ctrl.rs +++ b/crates/oxide_vm/src/vm_dispatch_ctrl.rs @@ -1,4 +1,4 @@ -use crate::vm::{Completion, FrameArgs, FrameContinuation, PendingAsyncEscape, TryHandler, Vm}; +use crate::vm::{Completion, ConstructArgs, FrameArgs, FrameContinuation, PendingAsyncEscape, TryHandler, Vm}; use crate::vm_dispatch_misc::DisposePhase; use crate::vm_trace; use oxide_bytecode::opcode; @@ -91,9 +91,7 @@ impl Vm { first: first_arg_reg, count: arg_count, }, - None, - None, - JsValue::undefined(), + ConstructArgs::none(), FrameContinuation::None, call_window, )?; diff --git a/crates/oxide_vm/src/vm_dispatch_misc.rs b/crates/oxide_vm/src/vm_dispatch_misc.rs index d7564050..1e3392e9 100644 --- a/crates/oxide_vm/src/vm_dispatch_misc.rs +++ b/crates/oxide_vm/src/vm_dispatch_misc.rs @@ -1,6 +1,6 @@ use crate::vm::{ - Completion, DisposeResumeKind, ForInIter, FrameArgs, FrameContinuation, PendingAsyncDispose, TryHandler, Vm, - MAX_PROTO_CHAIN_DEPTH, + Completion, ConstructArgs, DisposeResumeKind, ForInIter, FrameArgs, FrameContinuation, PendingAsyncDispose, + TryHandler, Vm, MAX_PROTO_CHAIN_DEPTH, }; use crate::vm_trace; use oxide_builtins::iterator::is_callable; @@ -200,9 +200,7 @@ impl Vm { first: first_arg_reg, count: arg_count, }, - Some(rd as u8), - Some(new_obj_val), - constructor, + ConstructArgs::new(rd as u8, new_obj_val, constructor), FrameContinuation::None, call_window, )?; @@ -346,9 +344,7 @@ impl Vm { target_val, this_value, FrameArgs::Slice(&call_args), - Some(rd as u8), - Some(new_obj_val), - target_val, + ConstructArgs::new(rd as u8, new_obj_val, target_val), FrameContinuation::None, call_window, )?; @@ -1586,6 +1582,7 @@ mod tests { use oxide_bytecode::opcode; use crate::vm_state::ForOfEntry; + use crate::vm_support::FunctionFlags; #[test] fn for_of_close_pops_iterator_stack() { @@ -1634,7 +1631,7 @@ mod tests { // 调用方实参区 regs[1..3):arg0=10, arg1=20;regs[2] 同时是 callee 形参槽(param_base=2) vm.regs[1] = JsValue::int(10); vm.regs[2] = JsValue::int(20); - vm.regs[5] = vm.create_function_object(1, vm.current_gen, false, false, false, false); + vm.regs[5] = vm.create_function_object(1, vm.current_gen, FunctionFlags::none()); vm.dispatch_new_expression(0, 5, 1).expect("NEW 压帧成功"); diff --git a/crates/oxide_vm/src/vm_props.rs b/crates/oxide_vm/src/vm_props.rs index 5a13172c..59cde92b 100644 --- a/crates/oxide_vm/src/vm_props.rs +++ b/crates/oxide_vm/src/vm_props.rs @@ -1,4 +1,4 @@ -use crate::vm::{FrameArgs, FrameContinuation, Vm, MAX_PROTO_CHAIN_DEPTH}; +use crate::vm::{ConstructArgs, FrameArgs, FrameContinuation, Vm, MAX_PROTO_CHAIN_DEPTH}; use crate::{ic_trace, vm_trace}; use oxide_kernel::prop_forge::PropTemplate; use oxide_kernel::shape_forge::EMPTY_SHAPE_ID; @@ -8,6 +8,34 @@ use oxide_types::arguments_map::ArgumentsMapState; use oxide_types::object::{JsObject, PropAttributes, PropMetaEntry}; use oxide_types::value::JsValue; +/// 写路径三布尔调用契约:帧化(setter 压帧)、严格性、builtin 入口。 +/// +/// 按值传递的 Copy 结构体,字段数三;三个入口薄包装各给一个关联构造器, +/// 调用点整体传值,避免三布尔散参。 +#[derive(Clone, Copy)] +pub(crate) struct SetContract { + use_frame_push: bool, + strict: bool, + builtin: bool, +} + +impl SetContract { + /// 字节码入口(ordinary_set / member 写):不帧化、非 builtin,严格性由调用点给。 + pub(crate) const fn bytecode(strict: bool) -> Self { + Self { use_frame_push: false, strict, builtin: false } + } + + /// builtin 入口(ordinary_set_builtin):不帧化、builtin,严格性由调用点给。 + pub(crate) const fn builtin(strict: bool) -> Self { + Self { use_frame_push: false, strict, builtin: true } + } + + /// 分发入口(ordinary_set_dispatch / IC 写):帧化、非 builtin,严格性由调用点给。 + pub(crate) const fn dispatch(strict: bool) -> Self { + Self { use_frame_push: true, strict, builtin: false } + } +} + impl Vm { /// 判定 mapped arguments 映射是否存活:创建帧仍在帧栈上且帧身份匹配。 /// @@ -229,9 +257,7 @@ impl Vm { getter, receiver, FrameArgs::Slice(&[]), - None, - None, - JsValue::undefined(), + ConstructArgs::none(), FrameContinuation::AccessorGet { target_reg }, 0, )?; @@ -356,7 +382,7 @@ impl Vm { pub(crate) fn ordinary_set( &mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, strict: bool, ) -> Result<(), String> { - self.ordinary_set_inner(obj, prop_name_si, val, receiver, false, strict, false) + self.ordinary_set_inner(obj, prop_name_si, val, receiver, SetContract::bytecode(strict)) } /// builtin 内部写入口:失败一律返回格式化 `Err` 由调用边界恢复为异常对象, @@ -365,24 +391,22 @@ impl Vm { pub(crate) fn ordinary_set_builtin( &mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, strict: bool, ) -> Result<(), String> { - self.ordinary_set_inner(obj, prop_name_si, val, receiver, false, strict, true) + self.ordinary_set_inner(obj, prop_name_si, val, receiver, SetContract::builtin(strict)) } /// 分发期入口:值直接落位。 pub(crate) fn ordinary_set_dispatch( &mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, strict: bool, ) -> Result<(), String> { - self.ordinary_set_inner(obj, prop_name_si, val, receiver, true, strict, false) + self.ordinary_set_inner(obj, prop_name_si, val, receiver, SetContract::dispatch(strict)) } - #[expect( - clippy::too_many_arguments, - reason = "写路径须透传 receiver、帧化与 builtin 三组调用契约标志" - )] fn ordinary_set_inner( - &mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, use_frame_push: bool, - strict: bool, builtin: bool, + &mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, contract: SetContract, ) -> Result<(), String> { + let strict = contract.strict; + let builtin = contract.builtin; + let use_frame_push = contract.use_frame_push; vm_trace!( "ordinary_set_inner: shape={} prop_si={} frame_push={}", obj.shape_id(), @@ -448,16 +472,7 @@ impl Vm { if (index as usize) >= live { return Ok(()); } - return self.set_to_receiver( - obj, - prop_name_si, - val, - receiver, - index as usize, - use_frame_push, - strict, - builtin, - ); + return self.set_to_receiver(prop_name_si, val, receiver, index as usize, builtin); } oxide_builtins::typed_array::TaIndexGate::NumericInvalid => { // 强转(副作用/抛错先触发)后按 live 复判落位;receiver @@ -681,10 +696,8 @@ impl Vm { /// /// # 副作用 /// - 可能写 receiver 的 buffer / 属性存储;强转副作用与自写臂同。 - #[allow(clippy::too_many_arguments)] fn set_to_receiver( - &mut self, _ta_obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, index: usize, - _use_frame_push: bool, _strict: bool, builtin: bool, + &mut self, prop_name_si: u32, val: JsValue, receiver: JsValue, index: usize, builtin: bool, ) -> Result<(), String> { let receiver_ptr = receiver.as_js_object_ptr(); if receiver_ptr.is_null() { @@ -767,9 +780,7 @@ impl Vm { setter, receiver, FrameArgs::Slice(&[val]), - None, - None, - JsValue::undefined(), + ConstructArgs::none(), FrameContinuation::AccessorSet, 0, )?; @@ -877,7 +888,7 @@ impl Vm { // 元素区写),与 dispatch_ic_set_prop 对称,防快路径建影子槽破坏数组语义。 self.ordinary_set(obj, prop_name_si, val, receiver, strict)?; } else { - self.create_named_prop_fast(obj, prop_name_si, val, receiver, ext_pc, false, strict)?; + self.create_named_prop_fast(obj, prop_name_si, val, receiver, ext_pc, SetContract::bytecode(strict))?; } Ok(()) } @@ -888,13 +899,15 @@ impl Vm { /// # 边界与前提 /// - 调用方已确认属性不存在于 shape 链(lookup_position miss)。 /// - 数组 length / 数组与 TA 整数索引键不进入本路径(调用方先分流到 ordinary_set)。 - /// - `use_frame_push` 与 ordinary_set* 入口一致(member 写 false / IC_SET 分发 true)。 + /// - `contract` 与 ordinary_set* 入口一致(member 写 bytecode / IC_SET 分发 dispatch); + /// builtin 位恒 false,本路径不消费。 /// - `strict` 为写方的严格模式:原型链只读/无 setter/不可扩展时严格抛错、sloppy 静默 no-op。 - #[allow(clippy::too_many_arguments)] pub(crate) fn create_named_prop_fast( &mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, ext_pc: usize, - use_frame_push: bool, strict: bool, + contract: SetContract, ) -> Result<(), String> { + let strict = contract.strict; + let use_frame_push = contract.use_frame_push; // 原型链同名 accessor 须触发 setter、只读 data 须报错(与 ordinary_set 一致), // 命中时不得创建 own 属性(规范 [[Set]] shadow 语义)。 if let Some(meta) = self.inherited_property_meta(obj, prop_name_si) { diff --git a/crates/oxide_vm/src/vm_runtime.rs b/crates/oxide_vm/src/vm_runtime.rs index 7621c5b9..9e9260d0 100644 --- a/crates/oxide_vm/src/vm_runtime.rs +++ b/crates/oxide_vm/src/vm_runtime.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, OnceLock}; use oxide_bytecode::module::CompiledModule; use oxide_bytecode::opcode::OpCode; -use crate::vm::{CallFrame, FrameArgs, FrameContinuation, InlineSyncState, TableGen, Vm}; +use crate::vm::{CallFrame, ConstructArgs, FrameArgs, FrameContinuation, InlineSyncState, TableGen, Vm}; use crate::vm_dispatch_misc::DisposePhase; use crate::{vm_debug, vm_info, vm_trace, vm_warn}; use oxide_types::object::{Cell, JsObject}; @@ -383,9 +383,7 @@ impl Vm { callee, this_value, FrameArgs::Slice(args), - None, - None, - JsValue::undefined(), + ConstructArgs::none(), FrameContinuation::None, 0, ) diff --git a/crates/oxide_vm/src/vm_support.rs b/crates/oxide_vm/src/vm_support.rs index f64cd800..f8ab3f51 100644 --- a/crates/oxide_vm/src/vm_support.rs +++ b/crates/oxide_vm/src/vm_support.rs @@ -26,6 +26,56 @@ fn gc_pressure_mode_from_env() -> bool { std::env::var_os("OXIDE_GC_PRESSURE").is_some() } +/// 函数种类标志位集合:箭头、类构造器、派生构造器,压缩在单个 `u8` 中。 +/// +/// 位定义:bit0 = arrow,bit1 = class_constructor,bit2 = derived_constructor。 +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct FunctionFlags(pub u8); + +impl FunctionFlags { + /// 箭头函数标志位(bit0)。 + pub(crate) const ARROW: u8 = 0b001; + /// 类构造器标志位(bit1)。 + pub(crate) const CLASS_CONSTRUCTOR: u8 = 0b010; + /// 派生构造器标志位(bit2)。 + pub(crate) const DERIVED_CONSTRUCTOR: u8 = 0b100; + + /// 无标志(普通函数)。 + pub(crate) const fn none() -> Self { + Self(0) + } + + /// 由三个布尔标志构造位集。 + pub(crate) const fn new(is_arrow: bool, is_class_constructor: bool, is_derived_constructor: bool) -> Self { + let mut bits = 0; + if is_arrow { + bits |= Self::ARROW; + } + if is_class_constructor { + bits |= Self::CLASS_CONSTRUCTOR; + } + if is_derived_constructor { + bits |= Self::DERIVED_CONSTRUCTOR; + } + Self(bits) + } + + /// 是否箭头函数。 + pub(crate) const fn is_arrow(self) -> bool { + self.0 & Self::ARROW != 0 + } + + /// 是否类构造器。 + pub(crate) const fn is_class_constructor(self) -> bool { + self.0 & Self::CLASS_CONSTRUCTOR != 0 + } + + /// 是否派生构造器。 + pub(crate) const fn is_derived_constructor(self) -> bool { + self.0 & Self::DERIVED_CONSTRUCTOR != 0 + } +} + impl Vm { /// Cons(rope)节点保留的单元阈值:拼接总长(UTF-16 单元数)≤ 该值时 /// 急切扁平。小链的"链接 + 首次消费扁平化"双重分配高于直接拷贝,直接 @@ -756,16 +806,13 @@ impl Vm { } /// 为 BytecodeFunc 常量创建函数 JsObject。 - /// 当 `is_arrow` 为 true 时,捕获当前 `this`(regs[254]),供调用时词法 this 绑定。 + /// 箭头标志置位时,捕获当前 `this`(regs[254]),供调用时词法 this 绑定。 /// /// # 边界与前提 /// - `gen` 为函数对象所属表代际:`sub_idx` 的口径与对象头的 `table_gen` /// 盖写均以它为准(闭包创建传执行帧代际,动态构造传当前代际——动态扩表 /// 追加进当前代际平表)。 - pub(crate) fn create_function_object( - &mut self, sub_idx: u32, gen: u32, is_arrow: bool, is_class_constructor: bool, is_derived_constructor: bool, - needs_home_object: bool, - ) -> JsValue { + pub(crate) fn create_function_object(&mut self, sub_idx: u32, gen: u32, flags: FunctionFlags) -> JsValue { // 生成器函数对象:原型为 %GeneratorFunction.prototype%(constructor 链解析到 // "GeneratorFunction"),且不像普通函数那样拥有 `prototype` 属性。 // 标志按函数对象所属代际平表解析:跨 run 调用时执行帧代际可异于当前代际, @@ -790,10 +837,9 @@ impl Vm { // 记录创建期表代际:调用点按 (table_gen, sub_module_index) 解析子模块 // 平表,跨 run 换表后存活函数仍命中原表(注册表按代际保活)。 obj.set_table_gen(gen); - obj.set_class_constructor(is_class_constructor); - obj.set_derived_constructor(is_derived_constructor); - let _ = needs_home_object; - if is_arrow { + obj.set_class_constructor(flags.is_class_constructor()); + obj.set_derived_constructor(flags.is_derived_constructor()); + if flags.is_arrow() { obj.set_arrow(true); obj.set_captured_this(self.regs[254]); } @@ -803,7 +849,7 @@ impl Vm { let obj_ptr = self.alloc_session_object(obj); let func_val = JsValue::object(obj_ptr as *mut u8); - if !is_arrow && !(is_async && !is_generator) { + if !flags.is_arrow() && !(is_async && !is_generator) { // 原型对象自身的 [[Prototype]]:生成器为 %GeneratorPrototype%,普通函数为 Object.prototype。 // 纯异步函数(非生成器)无 `prototype` 属性:规范不为其建 prototype 子对象。 let proto_of_proto = if is_async_generator {