mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
feat: server 执行请求路径,六段纯函数加每请求步数覆盖
This commit is contained in:
@@ -92,7 +92,9 @@ impl Vm {
|
||||
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;
|
||||
// 步数上限取每请求覆盖值.or(内核配置):覆盖优先、None 回退内核配置,
|
||||
// 未设覆盖的宿主(CLI/REPL/bench/test262)读到的值与改动前逐位一致。
|
||||
let max_steps = self.max_steps_override.or(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 不推进、
|
||||
|
||||
@@ -391,6 +391,10 @@ pub struct Vm {
|
||||
/// `pc/opcode/flat_id/frames`,供监督者超时/崩溃杀子进程后读回挂死点;
|
||||
/// 默认 None(零输出零分配)。
|
||||
pub(crate) pc_watch: Option<PathBuf>,
|
||||
/// 每请求步数上限覆盖:执行路径按请求设置,None 回退内核配置。
|
||||
/// 池回收的 `full_reset` 路径清位;`run()` 入口的 `clear_execution_state`
|
||||
/// 刻意不清(清在那会把执行路径刚设的覆盖抹掉)。
|
||||
pub(crate) max_steps_override: Option<u64>,
|
||||
}
|
||||
|
||||
impl Drop for Vm {
|
||||
@@ -467,6 +471,13 @@ impl Vm {
|
||||
self.pc_watch = path;
|
||||
}
|
||||
|
||||
/// 设置每请求步数上限覆盖:dispatch 主循环取 `覆盖值.or(内核配置)`,
|
||||
/// 覆盖优先、None 回退内核配置。执行路径按请求必设(含 None),池回收的
|
||||
/// `full_reset` 路径清位。
|
||||
pub fn set_max_steps(&mut self, limit: Option<u64>) {
|
||||
self.max_steps_override = limit;
|
||||
}
|
||||
|
||||
/// 设置指令周期采样周期(2 的幂,0 关闭)。开启后 dispatch 主循环每
|
||||
/// `period` 条指令记一条样本(flat_id、pc、opcode、frames 深度),run 末
|
||||
/// 按 flat_id 聚合并向 stderr 输出 top-K 直方图;关闭时热路径仅一次
|
||||
|
||||
@@ -179,6 +179,12 @@ impl VmGuard {
|
||||
pub fn vm_mut(&mut self) -> &mut Vm {
|
||||
self.vm.as_mut().expect("VmGuard has no VM")
|
||||
}
|
||||
|
||||
/// 显式标记被借出的 VM 为 dirty:`Drop` 时丢弃该 VM 并新建替补,
|
||||
/// 不对其执行 `full_reset`。供并发与未来显式弃用场景使用。
|
||||
pub fn mark_dirty(&mut self) {
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VmGuard {
|
||||
@@ -189,7 +195,9 @@ impl Drop for VmGuard {
|
||||
|
||||
let mut inner = self.pool.inner.lock().unwrap();
|
||||
|
||||
if self.dirty {
|
||||
// panic 展开期(thread::panicking 为真)被 drop 的 VM 一律按 dirty 丢弃:
|
||||
// 损坏 VM 上执行 full_reset 可能二次 panic,unwind 中二次 panic 即 abort。
|
||||
if self.dirty || std::thread::panicking() {
|
||||
vm_debug!("pool: discarding dirty vm");
|
||||
let new_vm = self.pool.replace_vm();
|
||||
inner.available.push(new_vm);
|
||||
|
||||
@@ -166,6 +166,7 @@ impl Vm {
|
||||
saved_table_gen_stack: Vec::new(),
|
||||
trace_instructions: false,
|
||||
pc_watch: None,
|
||||
max_steps_override: None,
|
||||
};
|
||||
vm.init_generator_intrinsics();
|
||||
vm.init_promise_intrinsics();
|
||||
@@ -309,6 +310,7 @@ impl Vm {
|
||||
saved_table_gen_stack: Vec::new(),
|
||||
trace_instructions: false,
|
||||
pc_watch: None,
|
||||
max_steps_override: None,
|
||||
};
|
||||
vm.init_generator_intrinsics();
|
||||
vm.init_promise_intrinsics();
|
||||
@@ -429,6 +431,9 @@ impl Vm {
|
||||
self.symbols.reset();
|
||||
self.root_reg_limit = 0;
|
||||
self.active_reg_limit = 0;
|
||||
// 步数上限覆盖随池回收清位:执行路径按请求必设覆盖(含 None),
|
||||
// 此处清位保证回收的 VM 不带旧覆盖回到默认态,循环 VM 回到内核配置。
|
||||
self.max_steps_override = None;
|
||||
}
|
||||
|
||||
/// 释放全部 session 堆数据:session 对象(本体 + 堆数据 + upvalue 列表)
|
||||
|
||||
@@ -1114,3 +1114,57 @@ fn full_reset_clears_symbol_state() {
|
||||
assert!(vm.symbols.symbol_descriptions.is_empty());
|
||||
assert!(vm.symbols.symbol_registry.is_empty());
|
||||
}
|
||||
|
||||
/// 编译源文本为模块(供步数上限测试直接 `run` 并检查 `Result`)。
|
||||
fn compile_module(source: &str) -> Arc<oxide_bytecode::module::CompiledModule> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse(&allocator, source).expect("parse failed");
|
||||
let module = oxide_compiler::compiler::Compiler::new()
|
||||
.compile(&program)
|
||||
.expect("compile failed");
|
||||
Arc::new(module)
|
||||
}
|
||||
|
||||
/// 步数覆盖超限:`set_max_steps(Some(100))` 加无限循环返回 `Err`,文本含 `step limit`。
|
||||
#[test]
|
||||
fn max_steps_override_exceeded_returns_err() {
|
||||
let mut vm = Vm::new();
|
||||
vm.set_max_steps(Some(100));
|
||||
let module = compile_module("for(;;){}");
|
||||
let result = vm.run(&module);
|
||||
assert!(result.is_err(), "无限循环带步数覆盖应返回 Err:{result:?}");
|
||||
let err = result.unwrap_err();
|
||||
assert!(err.contains("step limit"), "错误文本应含 step limit:{err}");
|
||||
}
|
||||
|
||||
/// 覆盖随 `full_reset` 清除:`Some(100)` 超限失败后 `full_reset`,再跑 50 轮循环
|
||||
/// (步数远超 100)返回 `Ok`,证明覆盖值未残留(回退内核配置无上限)。
|
||||
#[test]
|
||||
fn full_reset_clears_max_steps_override() {
|
||||
let mut vm = Vm::new();
|
||||
vm.set_max_steps(Some(100));
|
||||
let infinite = compile_module("for(;;){}");
|
||||
assert!(vm.run(&infinite).is_err(), "无限循环应超限");
|
||||
|
||||
vm.full_reset();
|
||||
|
||||
// 50 轮循环步数远超 100:覆盖清除后无上限,应返回 Ok。
|
||||
let moderate = compile_module("let n = 0; for (let i = 0; i < 50; i++) { n += i; } n");
|
||||
assert!(vm.run(&moderate).is_ok(), "full_reset 后 50 轮循环不应被旧覆盖限制");
|
||||
}
|
||||
|
||||
/// `set_max_steps(None)` 回退内核配置:内核配置 `max_steps` 置 `Some(100)` 的独立
|
||||
/// kernel 上,覆盖置 None 后超限仍被限(`or` 回退语义)。
|
||||
#[test]
|
||||
fn max_steps_none_falls_back_to_kernel_config() {
|
||||
let mut config = KernelConfig::minimal();
|
||||
config.max_steps = Some(100);
|
||||
let core = KernelCore::new(config);
|
||||
let mut vm = Vm::with_kernel_core(Arc::clone(&core));
|
||||
vm.set_max_steps(None);
|
||||
let module = compile_module("for(;;){}");
|
||||
let result = vm.run(&module);
|
||||
assert!(result.is_err(), "内核配置限步下无限循环应返回 Err:{result:?}");
|
||||
let err = result.unwrap_err();
|
||||
assert!(err.contains("step limit"), "错误文本应含 step limit:{err}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user