diff --git a/Cargo.lock b/Cargo.lock index 490a1a78..244d26b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.8.68" +version = "0.8.69" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.8.68" +version = "0.8.69" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.8.68" +version = "0.8.69" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.8.68" +version = "0.8.69" dependencies = [ "ansi_term", "bumpalo", @@ -1225,7 +1225,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.8.68" +version = "0.8.69" dependencies = [ "lru", "oxide_bytecode", @@ -1234,7 +1234,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.8.68" +version = "0.8.69" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1246,6 +1246,7 @@ dependencies = [ "oxide_log", "oxide_parser", "oxide_regalloc", + "oxide_runtime_api", "rustc-hash", "serde", "serde_json", @@ -1253,7 +1254,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.8.68" +version = "0.8.69" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1267,7 +1268,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.8.68" +version = "0.8.69" dependencies = [ "num-bigint", "oxc_allocator", @@ -1282,7 +1283,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.8.68" +version = "0.8.69" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1291,7 +1292,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.8.68" +version = "0.8.69" dependencies = [ "bumpalo", "dashmap", @@ -1305,7 +1306,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.8.68" +version = "0.8.69" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1317,7 +1318,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.8.68" +version = "0.8.69" dependencies = [ "tracing", "tracing-appender", @@ -1326,7 +1327,7 @@ dependencies = [ [[package]] name = "oxide_parser" -version = "0.8.68" +version = "0.8.69" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1341,7 +1342,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.8.68" +version = "0.8.69" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1357,10 +1358,11 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.8.68" +version = "0.8.69" dependencies = [ "num-bigint", "num-traits", + "oxide_bytecode", "oxide_kernel", "oxide_log", "oxide_types", @@ -1369,7 +1371,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.8.68" +version = "0.8.69" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1386,7 +1388,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.8.68" +version = "0.8.69" dependencies = [ "bumpalo", "dashmap", @@ -1399,7 +1401,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.8.68" +version = "0.8.69" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 24b9491f..525018ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ members = [ ] [workspace.package] -version = "0.8.68" +version = "0.8.69" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_builtins/tests/array_boundary_tests.rs b/crates/oxide_builtins/tests/array_boundary_tests.rs index fde55179..c28de636 100644 --- a/crates/oxide_builtins/tests/array_boundary_tests.rs +++ b/crates/oxide_builtins/tests/array_boundary_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -9,6 +10,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } diff --git a/crates/oxide_builtins/tests/builtin_overflow_boundary_tests.rs b/crates/oxide_builtins/tests/builtin_overflow_boundary_tests.rs index 6523c0aa..48b9c2a7 100644 --- a/crates/oxide_builtins/tests/builtin_overflow_boundary_tests.rs +++ b/crates/oxide_builtins/tests/builtin_overflow_boundary_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -9,6 +10,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } diff --git a/crates/oxide_builtins/tests/builtins_json_tests.rs b/crates/oxide_builtins/tests/builtins_json_tests.rs index e11de5ae..5c81d1df 100644 --- a/crates/oxide_builtins/tests/builtins_json_tests.rs +++ b/crates/oxide_builtins/tests/builtins_json_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_runtime_api::VmHost; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -10,6 +11,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } diff --git a/crates/oxide_builtins/tests/object_boundary_tests.rs b/crates/oxide_builtins/tests/object_boundary_tests.rs index f63714ca..8b2ac9e6 100644 --- a/crates/oxide_builtins/tests/object_boundary_tests.rs +++ b/crates/oxide_builtins/tests/object_boundary_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -9,6 +10,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } diff --git a/crates/oxide_builtins/tests/string_constructor_tests.rs b/crates/oxide_builtins/tests/string_constructor_tests.rs index 9467fdac..d1159693 100644 --- a/crates/oxide_builtins/tests/string_constructor_tests.rs +++ b/crates/oxide_builtins/tests/string_constructor_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -9,6 +10,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } @@ -101,6 +103,7 @@ fn number_to_string_cache_slot_correctness() { // 十六个槽位互异的值两轮各调一次:命中须键全等才返回, // 钉住槽位碰撞不得错返。 let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let mut seen = [false; 16]; for &d in &CACHE_TEST_VALUES { let slot = (d.to_bits() as usize) & 15; @@ -122,6 +125,7 @@ fn number_to_string_cache_survives_session_gc() { // 填满十六槽后强制完整 session 收集:缓存串已登记为 GC 根, // 收集后读回仍为原内容(漏根登记此测必挂)。 let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); for &d in &CACHE_TEST_VALUES { vm.number_to_string_cached(d); } @@ -144,6 +148,7 @@ fn number_to_string_cache_survives_session_gc() { fn number_to_string_cache_identity() { // 同值两次调用命中同槽:返回指针相等(命中复用 session 串)。 let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let a = vm.number_to_string_cached(2.5); let b = vm.number_to_string_cached(2.5); assert!(a.is_string() && b.is_string()); diff --git a/crates/oxide_cli/src/bench/leak_detect.rs b/crates/oxide_cli/src/bench/leak_detect.rs index 941951a9..6092dec8 100644 --- a/crates/oxide_cli/src/bench/leak_detect.rs +++ b/crates/oxide_cli/src/bench/leak_detect.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use std::time::Instant; use oxide_compiler::compiler::{compiled_module_hash, Compiler}; +use oxide_compiler::DefaultCompilerService; use oxide_kernel::kernel::{KernelConfig, KernelCore}; use oxide_parser::Allocator; use oxide_types::value::JsValue; @@ -225,6 +226,7 @@ pub fn run_mem_vm_creation_leak(kernel: &Arc) -> ExitCode { for i in 0..ITERATIONS { { let mut vm = Vm::with_kernel_core(Arc::clone(kernel)); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); if let Err(e) = vm.run(&module) { eprintln!("[vm_creation] iteration {i} run failed: {e}"); return ExitCode::FAILURE; @@ -318,6 +320,7 @@ pub fn run_mem_dirty_rebuild_leak(kernel: &Arc) -> ExitCode { const SAMPLE_EVERY: usize = 10; let mut vm = Vm::with_kernel_core(Arc::clone(kernel)); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let compiler = Compiler::new(); let mut sampler = LeakSampler::new(20); @@ -421,6 +424,7 @@ pub fn run_mem_closure_dead_leak(kernel: &Arc) -> ExitCode { let mut series: Vec<(usize, f64)> = Vec::new(); for window in 0..WINDOWS { let mut vm = Vm::with_kernel_core(Arc::clone(kernel)); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); for round in 0..ROUNDS_PER_WINDOW { if let Err(e) = vm.run(create) { eprintln!("[closure_dead_leak] window {window} round {round} create run failed: {e}"); @@ -479,6 +483,7 @@ pub fn run_mem_pool_high_water(kernel: &Arc) -> ExitCode { let light = compile_one(light_js); let mut vm = Vm::with_kernel_core(Arc::clone(kernel)); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); if let Err(e) = vm.run(&heavy) { eprintln!("[pool_high_water] heavy run failed: {e}"); return ExitCode::FAILURE; @@ -548,6 +553,7 @@ pub fn run_mem_object_churn_peak(kernel: &Arc) -> ExitCode { }; let mut vm = Vm::with_kernel_core(Arc::clone(kernel)); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let mut series: Vec<(usize, f64)> = Vec::new(); if let Some(kb) = read_vmrss_kb() { series.push((0, kb as f64)); @@ -652,6 +658,7 @@ pub fn run_mem_kernel_lifetime() -> ExitCode { let rss_pre = read_vmrss_kb().unwrap_or(0); { let mut vm = Vm::with_kernel_core(Arc::clone(&kernel)); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = match vm.run(&js_module) { Ok(v) => v, Err(e) => { @@ -769,7 +776,12 @@ pub fn run_mem_startup_breakdown() -> ExitCode { let t1 = Instant::now(); // 池构造:同步预热 min_size 个 Vm,预热成本计入本段。 - let pool = VmPool::new(Arc::clone(&kernel), config.min_pool_size, config.max_pool_size); + let pool = VmPool::new( + Arc::clone(&kernel), + Arc::new(DefaultCompilerService), + config.min_pool_size, + config.max_pool_size, + ); let t2 = Instant::now(); // 首次 spawn:命中预热池,近零成本。 @@ -904,6 +916,7 @@ mod tests { fn session_accounting_zero_after_full_reset() { let kernel = KernelCore::new(KernelConfig::standard()); let mut vm = Vm::with_kernel_core(Arc::clone(&kernel)); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let allocator = Allocator::default(); let program = oxide_parser::parse(&allocator, "var o = { a: 1 }; o").expect("parse"); let hash = compiled_module_hash(&program); diff --git a/crates/oxide_cli/src/main.rs b/crates/oxide_cli/src/main.rs index f017a25a..c9faa4cd 100644 --- a/crates/oxide_cli/src/main.rs +++ b/crates/oxide_cli/src/main.rs @@ -19,6 +19,7 @@ use oxide_cli::server::spawn; use oxide_cli::server::watchdog; use oxide_compiler::compiler::{compiled_module_hash, Compiler}; use oxide_compiler::compiler_error; +use oxide_compiler::DefaultCompilerService; use oxide_kernel::kernel::{KernelConfig, KernelCore}; use oxide_kernel::shape_forge::ShapeForge; use oxide_kernel::string_forge::PermInterner; @@ -620,7 +621,12 @@ fn make_kernel(verbose: bool, quiet: bool) -> Arc { } fn make_pool(kernel: &Arc) -> Arc { - VmPool::new(Arc::clone(kernel), kernel.config.min_pool_size, kernel.config.max_pool_size) + VmPool::new( + Arc::clone(kernel), + Arc::new(DefaultCompilerService), + kernel.config.min_pool_size, + kernel.config.max_pool_size, + ) } fn eval( @@ -767,6 +773,8 @@ fn repl() -> ExitCode { let kernel = make_kernel(false, false); let mut vm = Vm::with_kernel_core(Arc::clone(&kernel)); + // REPL 源经 eval 路径动态编译(含 `new Function` / eval 内置),注入真实编译服务。 + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let mut input_buf = String::new(); loop { diff --git a/crates/oxide_cli/src/server/eval.rs b/crates/oxide_cli/src/server/eval.rs index ca5aa31c..ea73bb36 100644 --- a/crates/oxide_cli/src/server/eval.rs +++ b/crates/oxide_cli/src/server/eval.rs @@ -100,12 +100,13 @@ fn panic_payload_str(payload: &Box) -> String { #[cfg(test)] mod tests { use super::*; + use oxide_compiler::DefaultCompilerService; use oxide_kernel::kernel::KernelConfig; /// 测试环境:minimal 内核加单 VM 池(与池既有测试同口径)。 fn test_env() -> (Arc, Arc) { let kernel = KernelCore::new(KernelConfig::minimal()); - let pool = VmPool::new(Arc::clone(&kernel), 1, Some(2)); + let pool = VmPool::new(Arc::clone(&kernel), Arc::new(DefaultCompilerService), 1, Some(2)); (kernel, pool) } diff --git a/crates/oxide_cli/src/server/forge.rs b/crates/oxide_cli/src/server/forge.rs index d9d07614..25788c56 100644 --- a/crates/oxide_cli/src/server/forge.rs +++ b/crates/oxide_cli/src/server/forge.rs @@ -73,12 +73,13 @@ pub fn handle_forge_query( mod tests { use super::*; use crate::server::eval; + use oxide_compiler::DefaultCompilerService; use oxide_kernel::kernel::KernelConfig; /// 测试环境:minimal 内核加单 VM 池(与 eval 测试同口径)。 fn test_env() -> (Arc, Arc) { let kernel = KernelCore::new(KernelConfig::minimal()); - let pool = VmPool::new(Arc::clone(&kernel), 1, Some(2)); + let pool = VmPool::new(Arc::clone(&kernel), Arc::new(DefaultCompilerService), 1, Some(2)); (kernel, pool) } diff --git a/crates/oxide_cli/src/server/workers.rs b/crates/oxide_cli/src/server/workers.rs index 5b337441..4bbad0ac 100644 --- a/crates/oxide_cli/src/server/workers.rs +++ b/crates/oxide_cli/src/server/workers.rs @@ -13,6 +13,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{mpsc, Arc, Mutex}; use std::thread::JoinHandle; +use oxide_compiler::DefaultCompilerService; use oxide_kernel::kernel::KernelCore; use oxide_vm::vm_pool::{PoolCounters, VmPool}; @@ -111,7 +112,14 @@ pub fn spawn_workers( let counters = Arc::clone(&counters); handles.push(std::thread::spawn(move || { // 池在本线程上创建,永不跨线程移动(Vm 不是 Send)。 - let pool = VmPool::with_counters(Arc::clone(&kernel), min_pool_size, max_pool_size, counters); + // 编译服务随池构造注入:worker 池内 Vm 的 eval 动态编译面由此供给。 + let pool = VmPool::with_counters( + Arc::clone(&kernel), + Arc::new(DefaultCompilerService), + min_pool_size, + max_pool_size, + counters, + ); worker_loop(rx, kernel, pool); })); senders.push(tx); diff --git a/crates/oxide_compiler/Cargo.toml b/crates/oxide_compiler/Cargo.toml index db8965ee..fdbc5971 100644 --- a/crates/oxide_compiler/Cargo.toml +++ b/crates/oxide_compiler/Cargo.toml @@ -9,6 +9,7 @@ description = "OxideJS - AST to bytecode compiler" [dependencies] oxide_bytecode = { path = "../oxide_bytecode" } oxide_parser = { path = "../oxide_parser" } +oxide_runtime_api = { path = "../oxide_runtime_api" } oxide_log = { path = "../oxide_log" } oxide_dce = { path = "../oxide_dce" } oxide_cfg = { path = "../oxide_cfg" } diff --git a/crates/oxide_compiler/src/compiler_service.rs b/crates/oxide_compiler/src/compiler_service.rs new file mode 100644 index 00000000..d801a1b3 --- /dev/null +++ b/crates/oxide_compiler/src/compiler_service.rs @@ -0,0 +1,39 @@ +//! 默认编译服务:串联 `oxide_parser::parse` 与 `Compiler::compile`, +//! parse 错误映射与 `Allocator` 构造的唯一实现源。 + +use oxide_bytecode::module::CompiledModule; +use oxide_parser::Program; +use oxide_runtime_api::CompilerService; + +use crate::compiler::Compiler; + +/// 无状态默认编译服务:两方法均无内部可变状态, +/// `Arc` 可跨线程共享。 +pub struct DefaultCompilerService; + +impl CompilerService for DefaultCompilerService { + fn compile_script(&self, source: &str) -> Result { + // 局部分配器:AST 节点经 oxc bump 分配器分配,编译完成即弃。 + let allocator = oxide_parser::Allocator::default(); + let program = parse_program(&allocator, source)?; + // 动态路径源契约:调用方以源码域转义(`string_forge::source_escape`) + // 形态传源,故置 source_encoded。 + Compiler::new().with_source_encoded(true).compile(&program) + } + + fn compile_eval_script(&self, source: &str) -> Result { + let allocator = oxide_parser::Allocator::default(); + let program = parse_program(&allocator, source)?; + // eval 脚本:顶层 var/function 声明落全局属性 configurable:true。 + Compiler::new() + .with_eval_script(true) + .with_source_encoded(true) + .compile(&program) + } +} + +/// 解析源码,解析错误各条消息换行拼接为单一错误串。 +fn parse_program<'a>(allocator: &'a oxide_parser::Allocator, source: &'a str) -> Result, String> { + oxide_parser::parse(allocator, source) + .map_err(|errs| errs.into_iter().map(|e| e.message).collect::>().join("\n")) +} diff --git a/crates/oxide_compiler/src/lib.rs b/crates/oxide_compiler/src/lib.rs index 1f9c8b5f..68a58251 100644 --- a/crates/oxide_compiler/src/lib.rs +++ b/crates/oxide_compiler/src/lib.rs @@ -6,5 +6,8 @@ pub mod compiler; pub mod compiler_log; +pub mod compiler_service; pub mod flatten; pub mod hash; + +pub use compiler_service::DefaultCompilerService; diff --git a/crates/oxide_runtime_api/Cargo.toml b/crates/oxide_runtime_api/Cargo.toml index b6daae9a..7dec0389 100644 --- a/crates/oxide_runtime_api/Cargo.toml +++ b/crates/oxide_runtime_api/Cargo.toml @@ -7,6 +7,7 @@ rust-version.workspace = true description = "OxideJS - VmHost trait: the abstract Vm interface builtins are written against" [dependencies] +oxide_bytecode = { path = "../oxide_bytecode" } oxide_types = { path = "../oxide_types" } num-bigint = "0.4" num-traits = "0.2" diff --git a/crates/oxide_runtime_api/src/compiler_service.rs b/crates/oxide_runtime_api/src/compiler_service.rs new file mode 100644 index 00000000..f82e9720 --- /dev/null +++ b/crates/oxide_runtime_api/src/compiler_service.rs @@ -0,0 +1,22 @@ +//! 动态编译服务接口:`Vm` 经它把源码编译为 `CompiledModule`, +//! 解耦 `oxide_vm` 对 `oxide_compiler` / `oxide_parser` 的直接依赖。 + +use oxide_bytecode::module::CompiledModule; + +/// 动态编译服务:`Vm` 经它把源码编译为 `CompiledModule`。 +/// +/// 无状态实现 `Send + Sync`,`Arc` 可跨线程共享 +/// (worker 调度、多 realm 场景)。trait 对象安全,`Vm` 以 +/// `Arc` 持服务句柄。 +pub trait CompilerService: Send + Sync { + /// 编译普通脚本(source_encoded 形态),返回完整模块树 + /// (根 flat_id=0 + 子模块)。 + /// + /// 供 `Function` 构造器(wrap 源码)与 `$262.evalScript`(普通脚本)。 + fn compile_script(&self, source: &str) -> Result; + + /// 编译 eval 脚本(source_encoded + eval_script 形态),返回完整模块树。 + /// + /// 顶层 var/function 声明落全局属性 configurable:true。 + fn compile_eval_script(&self, source: &str) -> Result; +} diff --git a/crates/oxide_runtime_api/src/lib.rs b/crates/oxide_runtime_api/src/lib.rs index 8e1155c9..01dbac22 100644 --- a/crates/oxide_runtime_api/src/lib.rs +++ b/crates/oxide_runtime_api/src/lib.rs @@ -12,6 +12,8 @@ /// ECMAScript 强转函数族。 mod coercion; +/// 动态编译服务接口(`Vm` 经它解耦对编译器的直接依赖)。 +pub mod compiler_service; /// builtins 依赖的 `VmHost` 能力面。 mod host; /// builtin native 函数的三态返回值。 @@ -26,5 +28,6 @@ pub use coercion::{ to_string_full, to_string_value_full, to_uint32, to_units_full, well_known_symbol_name, write_number_into, ToPrimitiveHint, }; +pub use compiler_service::CompilerService; pub use host::VmHost; pub use native_result::NativeResult; diff --git a/crates/oxide_test262/src/runner.rs b/crates/oxide_test262/src/runner.rs index 7c243f8d..ac9182d9 100644 --- a/crates/oxide_test262/src/runner.rs +++ b/crates/oxide_test262/src/runner.rs @@ -11,6 +11,7 @@ use crate::judge::{ }; use crate::meta::{parse_meta, strip_meta, TestMeta}; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_kernel::kernel::{KernelConfig, KernelCore}; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -171,6 +172,8 @@ fn run_test_inner( }; let mut vm = Vm::with_kernel_core(Arc::clone(kernel)); + // test262 语料含 eval / Function 动态编译面,注入真实编译服务。 + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 监督者注入现场文件路径时开启 VM 的 last-pc 定频写(未注入时零开销)。 if let Some(watch) = pc_watch_path() { vm.set_pc_watch(Some(watch.clone())); diff --git a/crates/oxide_vm/Cargo.toml b/crates/oxide_vm/Cargo.toml index 61edee49..2f29cfae 100644 --- a/crates/oxide_vm/Cargo.toml +++ b/crates/oxide_vm/Cargo.toml @@ -13,8 +13,6 @@ oxide_runtime_api = { path = "../oxide_runtime_api" } oxide_builtins = { path = "../oxide_builtins" } oxide_types = { path = "../oxide_types" } oxide_log = { path = "../oxide_log" } -oxide_compiler = { path = "../oxide_compiler" } -oxide_parser = { path = "../oxide_parser" } bumpalo.workspace = true fast-float.workspace = true ryu.workspace = true @@ -34,6 +32,8 @@ proptest.workspace = true regress.workspace = true oxide_ir = { path = "../oxide_ir" } oxide_emit = { path = "../oxide_emit" } +oxide_compiler = { path = "../oxide_compiler" } +oxide_parser = { path = "../oxide_parser" } criterion = { version = "0.5", features = ["html_reports"] } [[bench]] diff --git a/crates/oxide_vm/src/vm/dynamic.rs b/crates/oxide_vm/src/vm/dynamic.rs index a86c615a..77512de0 100644 --- a/crates/oxide_vm/src/vm/dynamic.rs +++ b/crates/oxide_vm/src/vm/dynamic.rs @@ -1,14 +1,33 @@ //! 动态编译:`Function` 构造器与脚本动态编译入口,及子树 flat_id 重编号。 +//! 编译经 `Vm` 持有的 `CompilerService` 句柄完成(`self.compiler`), +//! 本 crate 生产代码不直接依赖 `oxide_compiler` / `oxide_parser`。 use std::sync::{Arc, OnceLock}; use oxide_bytecode::module::CompiledModule; use oxide_bytecode::opcode::{self, OpCode}; +use oxide_runtime_api::CompilerService; use oxide_types::object::PropAttributes; use oxide_types::value::JsValue; use super::Vm; +/// 缺省 no-op 编译服务:两方法均返 `Err`(错误消息指向「未安装编译服务」)。 +/// +/// 供不需要动态编译的 `Vm` 实例(构造器缺省值);生产 entry points 与 +/// 动态编译测试经 `set_compiler_service` 注入真实实现。 +pub(crate) struct NoopCompilerService; + +impl CompilerService for NoopCompilerService { + fn compile_script(&self, _source: &str) -> Result { + Err("dynamic compilation unavailable: no compiler service installed".to_string()) + } + + fn compile_eval_script(&self, _source: &str) -> Result { + Err("dynamic compilation unavailable: no compiler service installed".to_string()) + } +} + impl Vm { /// 动态编译函数(`Function` 构造器路径):把参数列表与函数体 wrap 成匿名函数 /// 源码,走完整编译链后取匿名函数模块追加进 VM 平表,返回对应函数对象。 @@ -57,15 +76,11 @@ impl Vm { let params_str = params.join(", "); let source = format!("{prefix} anonymous({params_str}\n) {{\n{body}\n}}"); - let allocator = oxide_parser::Allocator::default(); - let program = oxide_parser::parse(&allocator, &source) - .map_err(|errs| errs.into_iter().map(|e| e.message).collect::>().join("\n"))?; // 动态路径源契约:调用方以源码域转义(`string_forge::source_escape`) // 形态传源;正则字面量源切片经 `source_escape_to_key` 还原注入 // marker 后入池(编码源口径,区别于静态源的 `pool_key_plain`)。 - let mut module = oxide_compiler::compiler::Compiler::new() - .with_source_encoded(true) - .compile(&program)?; + // 编译经注入的编译服务完成(parse 与 compile 串联在实现侧)。 + let mut module = self.compiler.compile_script(&source)?; let anonymous = module.sub_modules.remove(0); // 形参数以编译结果为准:单个实参 "a,b,c" 拼接后解析为 3 个形参 // (ES 动态函数把非末位实参以逗号连接成参数串再解析)。 @@ -113,15 +128,9 @@ impl Vm { /// # 副作用 /// - 扩展当前代际平表(`tables[current_gen]`)与常量缓存。 pub fn create_dynamic_script(&mut self, code: &str) -> Result { - let allocator = oxide_parser::Allocator::default(); - let program = oxide_parser::parse(&allocator, code) - .map_err(|errs| errs.into_iter().map(|e| e.message).collect::>().join("\n"))?; // eval 脚本:顶层 var/function 声明落全局属性 configurable:true。 // 动态路径源契约同 `create_dynamic_function`(源码域转义形态传源)。 - let module = oxide_compiler::compiler::Compiler::new() - .with_eval_script(true) - .with_source_encoded(true) - .compile(&program)?; + let module = self.compiler.compile_eval_script(code)?; // 根模块 flat_id=0 传 base+1,重编号后落 base(避开 sub_module_index()==0 // 守卫)。make_mut 彼时平表 Arc 强引用唯一持有者是本表,原地扩展不分叉。 let table = self.current_table_mut(); @@ -157,15 +166,10 @@ impl Vm { /// # 副作用 /// - 扩展当前代际平表(`tables[current_gen]`)与常量缓存。 pub fn create_plain_dynamic_script(&mut self, code: &str) -> Result { - let allocator = oxide_parser::Allocator::default(); - let program = oxide_parser::parse(&allocator, code) - .map_err(|errs| errs.into_iter().map(|e| e.message).collect::>().join("\n"))?; // 普通脚本:顶层 var/function 声明落全局属性 configurable:false, // let/const 落全局词法环境。动态路径源契约同 `create_dynamic_function` // (源码域转义形态传源)。 - let module = oxide_compiler::compiler::Compiler::new() - .with_source_encoded(true) - .compile(&program)?; + let module = self.compiler.compile_script(code)?; // 根模块 flat_id=0 传 base+1,重编号后落 base(避开 sub_module_index()==0 // 守卫)。make_mut 彼时平表 Arc 强引用唯一持有者是本表,原地扩展不分叉。 let table = self.current_table_mut(); diff --git a/crates/oxide_vm/src/vm/mod.rs b/crates/oxide_vm/src/vm/mod.rs index eac8279e..136427d9 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 dynamic::NoopCompilerService; pub(crate) use frames::FrameArgs; pub use frames::{CallFrame, Completion, ForInIter, FrameContinuation, TryHandler}; pub(crate) use gc_hooks::RootGroup; @@ -175,6 +176,12 @@ pub struct Vm { pub(crate) active_immutables: *const [JsValue], pub(crate) frames: SmallVec<[CallFrame; 16]>, pub(crate) kernel_core: Arc, + /// 动态编译服务句柄:`Function` 构造器 / eval / `$262.evalScript` 经它编译 + /// 源码(`dynamic.rs` 三方法)。缺省为 no-op stub(返 `Err`),生产 entry + /// points 与动态编译测试经 `set_compiler_service` 注入真实实现。 + /// `Arc` 因 trait `Send + Sync` 而 Send + Sync, + /// 不破坏 `unsafe impl Send for Vm`。 + pub(crate) compiler: Arc, /// 每 VM 的 realm 组合:内核会话(builtin world 与 global 对象)、 /// session GC 簿记与 10 个内建原型槽(见 `realm` 模块)。以 `Arc` 持有: /// 可变组经 `RefCell` 内部可变性在 `&Arc` 下改写,teardown 归 @@ -445,6 +452,18 @@ impl Vm { &self.kernel_core } + /// 注入动态编译服务(`Function` 构造器 / eval / `$262.evalScript` 的编译面)。 + /// + /// # 边界与前提 + /// - 构造后缺省为 no-op stub(动态编译返 `Err`);需要动态编译的调用方 + /// (生产 entry points 与动态编译测试)须在首次动态编译前注入真实实现。 + /// + /// # 副作用 + /// - 替换 `compiler` 句柄(`Arc` 克隆,无其他状态变更)。 + pub fn set_compiler_service(&mut self, service: Arc) { + self.compiler = service; + } + /// 只读访问当前 session(builtin world 与 global object)。 /// /// 返回 `Ref` 守卫(session 入 `RefCell` 后无法再给稳定 `&`):调用方 diff --git a/crates/oxide_vm/src/vm_pool.rs b/crates/oxide_vm/src/vm_pool.rs index 37610d9b..461ca493 100644 --- a/crates/oxide_vm/src/vm_pool.rs +++ b/crates/oxide_vm/src/vm_pool.rs @@ -5,6 +5,7 @@ use std::time::Duration; use crate::vm::Vm; use crate::{vm_debug, vm_trace, vm_warn}; use oxide_kernel::kernel::KernelCore; +use oxide_runtime_api::CompilerService; struct VmPoolInner { available: Vec, @@ -74,6 +75,9 @@ impl PoolCounters { /// 归还(带 5 秒超时强制扩容兜底)。线程安全,可供多线程并发领取。 pub struct VmPool { kernel_core: Arc, + /// 动态编译服务句柄:构造期定、此后不可变,`new_vm` 逐个注入每个 Vm + /// (预热与增长路径同口径,无「预热后补注入」时序问题)。 + compiler: Arc, inner: Mutex, condvar: Condvar, max_size: Option, @@ -94,9 +98,12 @@ impl VmPool { /// 创建 VM 池并同步预热 `min_size` 个 Vm(数量受 `max_size` 钳制), /// 首次 `spawn` 直接命中池。`max_size` 为池上限,`None` 表示不限。 /// + /// `compiler` 为池内全部 Vm 的动态编译服务(构造期定、此后不可变)。 /// 计数器为本池私有(不与其他池共享)。 - pub fn new(kernel_core: Arc, min_size: usize, max_size: Option) -> Arc { - Self::with_counters(kernel_core, min_size, max_size, PoolCounters::shared()) + pub fn new( + kernel_core: Arc, compiler: Arc, min_size: usize, max_size: Option, + ) -> Arc { + Self::with_counters(kernel_core, compiler, min_size, max_size, PoolCounters::shared()) } /// 创建共享外部聚合计数器的 VM 池:多个池的原子增减累加到同一聚合, @@ -110,15 +117,18 @@ impl VmPool { /// # 边界与前提 /// - 计数器通常经 `PoolCounters::shared` 跨线程共享;池本体可跨线程移动 /// (Send/Sync),worker 经 spawn 独占借出 Vm。 + /// - `compiler` 在构造期固化:预热与增长路径经 `new_vm` 逐个注入同一服务。 /// /// # 副作用 /// - 同步创建 `min_size` 个 Vm。 pub fn with_counters( - kernel_core: Arc, min_size: usize, max_size: Option, counters: Arc, + kernel_core: Arc, compiler: Arc, min_size: usize, max_size: Option, + counters: Arc, ) -> Arc { let warm = min_size.min(max_size.unwrap_or(min_size)); let pool = Arc::new(Self { kernel_core: Arc::clone(&kernel_core), + compiler: Arc::clone(&compiler), inner: Mutex::new(VmPoolInner { available: Vec::new(), total_count: 0, @@ -129,7 +139,7 @@ impl VmPool { }); let mut inner = pool.inner.lock().unwrap(); for _ in 0..warm { - inner.available.push(Self::new_vm(&kernel_core)); + inner.available.push(pool.new_vm()); inner.total_count += 1; } drop(inner); @@ -138,12 +148,15 @@ impl VmPool { pool } - fn new_vm(core: &Arc) -> Vm { - Vm::with_kernel_core(Arc::clone(core)) + /// 新建一个 Vm 并注入本池的动态编译服务(预热与增长路径共用)。 + fn new_vm(&self) -> Vm { + let mut vm = Vm::with_kernel_core(Arc::clone(&self.kernel_core)); + vm.set_compiler_service(Arc::clone(&self.compiler)); + vm } fn replace_vm(&self) -> Vm { - Self::new_vm(&self.kernel_core) + self.new_vm() } /// 从池中借出一个 VM:优先复用空闲实例,否则在池未满时新建,池满则阻塞等待归还。 @@ -173,7 +186,7 @@ impl VmPool { drop(inner); self.counters.total.fetch_add(1, Ordering::Relaxed); self.counters.record_borrow(); - let vm = Self::new_vm(&self.kernel_core); + let vm = self.new_vm(); return VmGuard { vm: Some(vm), pool: Arc::clone(self), @@ -189,7 +202,7 @@ impl VmPool { drop(inner); self.counters.total.fetch_add(1, Ordering::Relaxed); self.counters.record_borrow(); - let vm = Self::new_vm(&self.kernel_core); + let vm = self.new_vm(); return VmGuard { vm: Some(vm), pool: Arc::clone(self), @@ -291,16 +304,22 @@ impl Drop for VmGuard { #[cfg(test)] mod tests { use super::*; + use oxide_compiler::DefaultCompilerService; use oxide_kernel::kernel::KernelConfig; fn test_kernel() -> Arc { KernelCore::new(KernelConfig::minimal()) } + /// 测试池的编译服务(池测试不 exercise 动态编译,缺省实现即可)。 + fn test_compiler() -> Arc { + Arc::new(DefaultCompilerService) + } + #[test] fn test_pool_spawn_returns_guard() { let kernel = test_kernel(); - let pool = VmPool::new(kernel, 1, None); + let pool = VmPool::new(kernel, test_compiler(), 1, None); let guard = pool.spawn(); drop(guard); } @@ -308,7 +327,7 @@ mod tests { #[test] fn test_pool_recycle_on_drop() { let kernel = test_kernel(); - let pool = VmPool::new(kernel, 1, None); + let pool = VmPool::new(kernel, test_compiler(), 1, None); let guard = pool.spawn(); drop(guard); let guard2 = pool.spawn(); @@ -318,7 +337,7 @@ mod tests { #[test] fn test_pool_grows_if_empty() { let kernel = test_kernel(); - let pool = VmPool::new(Arc::clone(&kernel), 1, Some(3)); + let pool = VmPool::new(Arc::clone(&kernel), test_compiler(), 1, Some(3)); let g1 = pool.spawn(); let g2 = pool.spawn(); drop(g1); @@ -328,7 +347,7 @@ mod tests { #[test] fn test_pool_warms_min_size_on_new() { let kernel = test_kernel(); - let pool = VmPool::new(kernel, 2, None); + let pool = VmPool::new(kernel, test_compiler(), 2, None); { let inner = pool.inner.lock().unwrap(); assert_eq!(inner.available.len(), 2); @@ -347,7 +366,7 @@ mod tests { #[test] fn test_pool_warmup_clamped_by_max_size() { let kernel = test_kernel(); - let pool = VmPool::new(kernel, 2, Some(1)); + let pool = VmPool::new(kernel, test_compiler(), 2, Some(1)); let inner = pool.inner.lock().unwrap(); assert_eq!(inner.available.len(), 1); assert_eq!(inner.total_count, 1); @@ -357,8 +376,8 @@ mod tests { fn test_with_counters_shared_aggregate() { let kernel = test_kernel(); let counters = PoolCounters::shared(); - let pool_a = VmPool::with_counters(Arc::clone(&kernel), 1, Some(4), Arc::clone(&counters)); - let pool_b = VmPool::with_counters(Arc::clone(&kernel), 2, Some(4), Arc::clone(&counters)); + let pool_a = VmPool::with_counters(Arc::clone(&kernel), test_compiler(), 1, Some(4), Arc::clone(&counters)); + let pool_b = VmPool::with_counters(Arc::clone(&kernel), test_compiler(), 2, Some(4), Arc::clone(&counters)); // 预热后聚合等于两池之和:总数 1 + 2 = 3,全部空闲。 assert_eq!(counters.total(), 3, "聚合总数应为两池预热之和"); @@ -383,7 +402,7 @@ mod tests { #[test] fn test_peak_count_single_thread_exact() { let kernel = test_kernel(); - let pool = VmPool::new(kernel, 2, None); + let pool = VmPool::new(kernel, test_compiler(), 2, None); assert_eq!(pool.peak_count(), 0, "从未借出的池峰值应为零"); let g1 = pool.spawn(); @@ -401,8 +420,8 @@ mod tests { fn test_peak_count_shared_aggregate() { let kernel = test_kernel(); let counters = PoolCounters::shared(); - let pool_a = VmPool::with_counters(Arc::clone(&kernel), 1, Some(4), Arc::clone(&counters)); - let pool_b = VmPool::with_counters(Arc::clone(&kernel), 1, Some(4), Arc::clone(&counters)); + let pool_a = VmPool::with_counters(Arc::clone(&kernel), test_compiler(), 1, Some(4), Arc::clone(&counters)); + let pool_b = VmPool::with_counters(Arc::clone(&kernel), test_compiler(), 1, Some(4), Arc::clone(&counters)); let g1 = pool_a.spawn(); let g2 = pool_b.spawn(); @@ -427,7 +446,7 @@ mod tests { std::thread::spawn(move || { // 每线程自建池、共享同一聚合计数器(Vm 经 unsafe impl Send 可 // 跨线程,本测试仍按每线程自有池验证计数器聚合)。 - let pool = VmPool::with_counters(kernel, 0, Some(8), counters); + let pool = VmPool::with_counters(kernel, test_compiler(), 0, Some(8), counters); for _ in 0..50 { let guard = pool.spawn(); drop(guard); @@ -447,7 +466,7 @@ mod tests { #[test] fn test_collect_idle_gc_returns_idle_count() { let kernel = test_kernel(); - let pool = VmPool::new(kernel, 1, None); + let pool = VmPool::new(kernel, test_compiler(), 1, None); let guard = pool.spawn(); drop(guard); assert_eq!(pool.collect_idle_gc(), 1, "归还一个空闲 VM 后收集数应为 1"); diff --git a/crates/oxide_vm/src/vm_support.rs b/crates/oxide_vm/src/vm_support.rs index eb473be1..64cbe1de 100644 --- a/crates/oxide_vm/src/vm_support.rs +++ b/crates/oxide_vm/src/vm_support.rs @@ -68,6 +68,9 @@ impl Vm { active_immutables: std::ptr::slice_from_raw_parts(std::ptr::null(), 0), frames: smallvec::SmallVec::new(), kernel_core: core, + // 缺省 no-op 编译服务:动态编译返 Err,生产 entry points 与 + // 动态编译测试经 set_compiler_service 注入真实实现。 + compiler: Arc::new(crate::vm::NoopCompilerService), realm: Arc::new(Realm { realm_id, session: RefCell::new(session), @@ -221,6 +224,9 @@ impl Vm { active_immutables: std::ptr::slice_from_raw_parts(std::ptr::null(), 0), frames: smallvec::SmallVec::new(), kernel_core: core, + // 缺省 no-op 编译服务:动态编译返 Err,生产 entry points 与 + // 动态编译测试经 set_compiler_service 注入真实实现。 + compiler: Arc::new(crate::vm::NoopCompilerService), realm: Arc::new(Realm { realm_id, session: RefCell::new(session), diff --git a/crates/oxide_vm/src/vm_support/tests.rs b/crates/oxide_vm/src/vm_support/tests.rs index ccc84a8f..704cf04e 100644 --- a/crates/oxide_vm/src/vm_support/tests.rs +++ b/crates/oxide_vm/src/vm_support/tests.rs @@ -1,6 +1,8 @@ //! vm_support 内联测试:全量重置状态清除与全局重建、分配上限、生成器与 BigInt 存活、动态编译及源文本断言行为。 use super::*; +use oxide_compiler::DefaultCompilerService; + fn global_prop(vm: &Vm, name: &str) -> JsValue { global_prop_opt(vm, name).expect("global slot should exist") } @@ -499,6 +501,7 @@ fn immutables_filled_once_per_module() { #[test] fn dynamic_function_basic_arity() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 与等价静态函数返回值逐位一致(引擎函数调用统一产 Double 数值)。 let expected = run_source(&mut vm, "function f(a,b){return a+b} f(3,4)"); let result = run_source(&mut vm, "new Function('a','b','return a+b')(3,4)"); @@ -508,6 +511,7 @@ fn dynamic_function_basic_arity() { #[test] fn dynamic_function_called_without_new() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let expected = run_source(&mut vm, "function f(a,b){return a*b} f(6,7)"); let result = run_source(&mut vm, "Function('a','b','return a*b')(6,7)"); assert_eq!(result, expected); @@ -516,12 +520,14 @@ fn dynamic_function_called_without_new() { #[test] fn dynamic_function_empty_body_returns_undefined() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); assert!(run_source(&mut vm, "Function()()").is_undefined()); } #[test] fn dynamic_function_syntax_error_throws_syntax_error() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = run_source(&mut vm, "try{new Function('return {{')}catch(e){e.name}"); assert!(result.is_string()); assert_eq!(vm.lookup_str(result).as_deref(), Some("SyntaxError")); @@ -530,6 +536,7 @@ fn dynamic_function_syntax_error_throws_syntax_error() { #[test] fn dynamic_function_nested_closure_renumbering() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 匿名函数体声明嵌套函数 g,返回值是引用 g 的闭包:验证子树 flat_id 重编号 // 与 CREATE_CLOSURE imm16 重写后嵌套调用仍指向正确的子模块。 let expected = run_source( @@ -546,6 +553,7 @@ fn dynamic_function_nested_closure_renumbering() { #[test] fn dynamic_function_multiple_in_one_run() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 同一 run 内连续创建多个动态函数:验证 base 偏移累计正确。 let expected = run_source( &mut vm, @@ -561,6 +569,7 @@ fn dynamic_function_multiple_in_one_run() { #[test] fn dynamic_function_name_and_length() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let name = run_source(&mut vm, "var f=new Function('a','b','return a'); f.name"); assert!(name.is_string()); assert_eq!(vm.lookup_str(name).as_deref(), Some("anonymous")); @@ -571,6 +580,7 @@ fn dynamic_function_name_and_length() { #[test] fn dynamic_function_comma_split_params_count() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 单个实参 "a,b,c" 拼接解析为 3 个形参,length 应为解析后的形参数。 let result = run_source(&mut vm, "new Function('a,b,c','null').length"); assert_eq!(result, JsValue::int(3)); @@ -579,6 +589,7 @@ fn dynamic_function_comma_split_params_count() { #[test] fn dynamic_function_name_and_length_attributes() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // length/name 为不可写、不可枚举、可配置的数据属性。 let attrs = run_source( &mut vm, @@ -595,6 +606,7 @@ fn dynamic_function_name_and_length_attributes() { #[test] fn dynamic_function_rethrows_to_string_exception() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 形参 ToString 回调抛出的原始值须原样传播,而非包成 TypeError。 let result = run_source(&mut vm, "try{new Function({toString:function(){throw 7}})}catch(e){e}"); assert_eq!(result, JsValue::int(7)); diff --git a/crates/oxide_vm/tests/arithmetic_tests.rs b/crates/oxide_vm/tests/arithmetic_tests.rs index 81530bee..036ef2f5 100644 --- a/crates/oxide_vm/tests/arithmetic_tests.rs +++ b/crates/oxide_vm/tests/arithmetic_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), @@ -27,6 +29,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse ok"); let module = Compiler::new().compile(&program).expect("compile ok"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let val = vm.run(&Arc::new(module)).expect("run ok"); if val.is_string() { vm.lookup_str(val).unwrap_or_default() diff --git a/crates/oxide_vm/tests/arrow_tests.rs b/crates/oxide_vm/tests/arrow_tests.rs index 7d4353b2..6109f611 100644 --- a/crates/oxide_vm/tests/arrow_tests.rs +++ b/crates/oxide_vm/tests/arrow_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -16,6 +17,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {}", e), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{}", result), Err(e) => format!("vm error: {}", e), @@ -33,6 +35,7 @@ fn eval_val(source: &str) -> (Vm, Result) { Err(e) => return (Vm::new(), Err(format!("compile error: {}", e))), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)); (vm, result) } diff --git a/crates/oxide_vm/tests/async_tests.rs b/crates/oxide_vm/tests/async_tests.rs index a117da29..217b9937 100644 --- a/crates/oxide_vm/tests/async_tests.rs +++ b/crates/oxide_vm/tests/async_tests.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::promise::promise_settled_value; use oxide_vm::vm::Vm; @@ -20,6 +21,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format_value(&vm, result), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/block_fn_async_gen_tests.rs b/crates/oxide_vm/tests/block_fn_async_gen_tests.rs index 203bb03f..47208f95 100644 --- a/crates/oxide_vm/tests/block_fn_async_gen_tests.rs +++ b/crates/oxide_vm/tests/block_fn_async_gen_tests.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -16,6 +17,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/block_fn_if_arm_var_shadow_tests.rs b/crates/oxide_vm/tests/block_fn_if_arm_var_shadow_tests.rs index e0b52f22..4d4f0a0c 100644 --- a/crates/oxide_vm/tests/block_fn_if_arm_var_shadow_tests.rs +++ b/crates/oxide_vm/tests/block_fn_if_arm_var_shadow_tests.rs @@ -10,6 +10,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -19,6 +20,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/block_fn_var_head_tests.rs b/crates/oxide_vm/tests/block_fn_var_head_tests.rs index 1d959492..c1eb3679 100644 --- a/crates/oxide_vm/tests/block_fn_var_head_tests.rs +++ b/crates/oxide_vm/tests/block_fn_var_head_tests.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -17,6 +18,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/block_function_decl_tests.rs b/crates/oxide_vm/tests/block_function_decl_tests.rs index a4505e60..86d40856 100644 --- a/crates/oxide_vm/tests/block_function_decl_tests.rs +++ b/crates/oxide_vm/tests/block_function_decl_tests.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -16,6 +17,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/block_scope_leave_tests.rs b/crates/oxide_vm/tests/block_scope_leave_tests.rs index 35d5809c..ae325e11 100644 --- a/crates/oxide_vm/tests/block_scope_leave_tests.rs +++ b/crates/oxide_vm/tests/block_scope_leave_tests.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -22,6 +23,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/builtins_array_tests.rs b/crates/oxide_vm/tests/builtins_array_tests.rs index ac3aa2cb..3cc9197e 100644 --- a/crates/oxide_vm/tests/builtins_array_tests.rs +++ b/crates/oxide_vm/tests/builtins_array_tests.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use oxide_builtins::array::{array_constructor, array_push}; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -10,6 +11,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } @@ -40,6 +42,7 @@ fn array_push_returns_length() { #[test] fn array_push_returns_true_length_beyond_31() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.set_reg(1, oxide_types::value::JsValue::int(31)); let array = array_constructor(&mut vm, &[0, 1]).unwrap(); vm.set_reg(0, array); diff --git a/crates/oxide_vm/tests/builtins_error_tests.rs b/crates/oxide_vm/tests/builtins_error_tests.rs index be886d82..d0e14325 100644 --- a/crates/oxide_vm/tests/builtins_error_tests.rs +++ b/crates/oxide_vm/tests/builtins_error_tests.rs @@ -2,13 +2,16 @@ use std::sync::Arc; use oxide_builtins::error; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::mem::P; use oxide_types::object::JsObject; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; fn make_vm() -> Vm { - Vm::new() + let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); + vm } fn eval(source: &str) -> Result { diff --git a/crates/oxide_vm/tests/builtins_function_tests.rs b/crates/oxide_vm/tests/builtins_function_tests.rs index 3489d85d..f9fc181c 100644 --- a/crates/oxide_vm/tests/builtins_function_tests.rs +++ b/crates/oxide_vm/tests/builtins_function_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -249,6 +250,7 @@ fn function_apply_non_callable_this_throws_catchable_type_error() { // 不可调用 this(实例原型链含函数)经 apply 转发:抛可捕获 TypeError, // 不得绕过 try/catch 成为引擎级错误。 let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let name = eval( &mut vm, "function FACTORY(){} FACTORY.prototype = Function(); var o = new FACTORY(); try { o.apply(); } catch (e) { e.name }", diff --git a/crates/oxide_vm/tests/builtins_globals_tests.rs b/crates/oxide_vm/tests/builtins_globals_tests.rs index 743a8d0a..5fae64f6 100644 --- a/crates/oxide_vm/tests/builtins_globals_tests.rs +++ b/crates/oxide_vm/tests/builtins_globals_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -10,6 +11,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -18,6 +20,7 @@ fn eval_with_vm(source: &str) -> (Vm, Result) { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)); (vm, result) } diff --git a/crates/oxide_vm/tests/builtins_object_tests.rs b/crates/oxide_vm/tests/builtins_object_tests.rs index ec500c68..c0bf8e9d 100644 --- a/crates/oxide_vm/tests/builtins_object_tests.rs +++ b/crates/oxide_vm/tests/builtins_object_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -9,6 +10,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } diff --git a/crates/oxide_vm/tests/builtins_typed_array_base64_tests.rs b/crates/oxide_vm/tests/builtins_typed_array_base64_tests.rs index 25279b82..444fddeb 100644 --- a/crates/oxide_vm/tests/builtins_typed_array_base64_tests.rs +++ b/crates/oxide_vm/tests/builtins_typed_array_base64_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -18,6 +19,7 @@ fn to_str(vm: &Vm, val: JsValue) -> String { #[test] fn to_base64_rfc4648_vectors() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -43,6 +45,7 @@ fn to_base64_rfc4648_vectors() { #[test] fn to_base64_alphabet_and_omit_padding() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -65,6 +68,7 @@ fn to_base64_alphabet_and_omit_padding() { #[test] fn to_base64_option_coercion_and_receiver() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -90,6 +94,7 @@ fn to_base64_option_coercion_and_receiver() { #[test] fn to_hex_and_receiver_validation() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -110,6 +115,7 @@ fn to_hex_and_receiver_validation() { #[test] fn set_from_base64_results_and_target_size() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -151,6 +157,7 @@ fn set_from_base64_results_and_target_size() { #[test] fn set_from_base64_last_chunk_handling() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -190,6 +197,7 @@ fn set_from_base64_last_chunk_handling() { #[test] fn set_from_base64_subarray_and_option_order() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -234,6 +242,7 @@ fn set_from_base64_subarray_and_option_order() { #[test] fn set_from_base64_writes_up_to_error() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -251,6 +260,7 @@ fn set_from_base64_writes_up_to_error() { #[test] fn set_from_hex_results_and_odd_length() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -285,6 +295,7 @@ fn set_from_hex_results_and_odd_length() { #[test] fn from_base64_static() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -330,6 +341,7 @@ fn from_base64_static() { #[test] fn from_hex_static() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -353,6 +365,7 @@ fn from_hex_static() { #[test] fn typed_array_prototype_to_string_chain() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -378,6 +391,7 @@ fn typed_array_prototype_to_string_chain() { #[test] fn clamped_inherits_base64_methods_but_rejects() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { @@ -401,6 +415,7 @@ fn clamped_inherits_base64_methods_but_rejects() { #[test] fn base64_method_metadata() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval( &mut vm, r#"(function() { diff --git a/crates/oxide_vm/tests/catch_param_capture_tests.rs b/crates/oxide_vm/tests/catch_param_capture_tests.rs index 698fe8f7..08fe265a 100644 --- a/crates/oxide_vm/tests/catch_param_capture_tests.rs +++ b/crates/oxide_vm/tests/catch_param_capture_tests.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -23,6 +24,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/coercion_tests.rs b/crates/oxide_vm/tests/coercion_tests.rs index 6ef0f5cc..20c76cd2 100644 --- a/crates/oxide_vm/tests/coercion_tests.rs +++ b/crates/oxide_vm/tests/coercion_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_runtime_api as coercion; use oxide_types::value::JsValue; @@ -17,6 +18,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), @@ -88,6 +90,7 @@ fn test_strict_equality_null_undefined() { #[test] fn test_to_int32_and_to_uint32() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let string_three = vm.new_string("3"); let string_bad = vm.new_string("x"); @@ -151,6 +154,7 @@ fn to_primitive_symbol_hint_invoked() { #[test] fn to_number_full_symbol_throws() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let sym = JsValue::symbol(0); let result = coercion::to_number_full(sym, &mut vm); assert!(result.is_err(), "to_number_full(Symbol) must error, got {result:?}"); @@ -323,6 +327,7 @@ fn eval_ty(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } diff --git a/crates/oxide_vm/tests/comparison_tests.rs b/crates/oxide_vm/tests/comparison_tests.rs index de561658..aa26bfc0 100644 --- a/crates/oxide_vm/tests/comparison_tests.rs +++ b/crates/oxide_vm/tests/comparison_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/compiler_alignment_binding_tests.rs b/crates/oxide_vm/tests/compiler_alignment_binding_tests.rs index 3f9dfe2a..2b107b60 100644 --- a/crates/oxide_vm/tests/compiler_alignment_binding_tests.rs +++ b/crates/oxide_vm/tests/compiler_alignment_binding_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/compiler_alignment_class_tests.rs b/crates/oxide_vm/tests/compiler_alignment_class_tests.rs index 4074121f..c095fe2d 100644 --- a/crates/oxide_vm/tests/compiler_alignment_class_tests.rs +++ b/crates/oxide_vm/tests/compiler_alignment_class_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/compiler_alignment_expr_tests.rs b/crates/oxide_vm/tests/compiler_alignment_expr_tests.rs index cc2e4975..111af2ab 100644 --- a/crates/oxide_vm/tests/compiler_alignment_expr_tests.rs +++ b/crates/oxide_vm/tests/compiler_alignment_expr_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/const_guard_tests.rs b/crates/oxide_vm/tests/const_guard_tests.rs index f1d6fa1b..76daad48 100644 --- a/crates/oxide_vm/tests/const_guard_tests.rs +++ b/crates/oxide_vm/tests/const_guard_tests.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -21,6 +22,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/control_flow_tests.rs b/crates/oxide_vm/tests/control_flow_tests.rs index f7134394..5a7e8198 100644 --- a/crates/oxide_vm/tests/control_flow_tests.rs +++ b/crates/oxide_vm/tests/control_flow_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/decl_lex_restricted_global_tests.rs b/crates/oxide_vm/tests/decl_lex_restricted_global_tests.rs index 2a744f41..2c2b292d 100644 --- a/crates/oxide_vm/tests/decl_lex_restricted_global_tests.rs +++ b/crates/oxide_vm/tests/decl_lex_restricted_global_tests.rs @@ -12,6 +12,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -20,6 +21,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/define_property_descriptor_tests.rs b/crates/oxide_vm/tests/define_property_descriptor_tests.rs index 79fbbeeb..ad0e9aa0 100644 --- a/crates/oxide_vm/tests/define_property_descriptor_tests.rs +++ b/crates/oxide_vm/tests/define_property_descriptor_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -9,6 +10,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } diff --git a/crates/oxide_vm/tests/delete_builtin_read_tests.rs b/crates/oxide_vm/tests/delete_builtin_read_tests.rs index 4e56a607..306f2c58 100644 --- a/crates/oxide_vm/tests/delete_builtin_read_tests.rs +++ b/crates/oxide_vm/tests/delete_builtin_read_tests.rs @@ -10,6 +10,7 @@ use std::sync::Arc; use oxide_bytecode::module::CompiledModule; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -25,6 +26,7 @@ fn eval_js(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("parse: {e:?}"))?; let module = Arc::new(Compiler::new().compile(&program).map_err(|e| format!("compile: {e}"))?); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let val = vm.run(&module)?; Ok((vm, val)) } diff --git a/crates/oxide_vm/tests/delete_eval_var_env_tests.rs b/crates/oxide_vm/tests/delete_eval_var_env_tests.rs index 28b107e8..f625389b 100644 --- a/crates/oxide_vm/tests/delete_eval_var_env_tests.rs +++ b/crates/oxide_vm/tests/delete_eval_var_env_tests.rs @@ -15,6 +15,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -23,6 +24,7 @@ fn eval_truthy(source: &str) { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); assert!(result.is_bool() && result.as_bool(), "expected true, got: {result:?}\nsource: {source}"); } diff --git a/crates/oxide_vm/tests/eval_block_fn_tests.rs b/crates/oxide_vm/tests/eval_block_fn_tests.rs index db3c0fb0..5a4b4aa6 100644 --- a/crates/oxide_vm/tests/eval_block_fn_tests.rs +++ b/crates/oxide_vm/tests/eval_block_fn_tests.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -14,6 +15,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -23,6 +25,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); vm.lookup_str(result).unwrap_or_else(|| format!("{result}")) } diff --git a/crates/oxide_vm/tests/eval_script_global_tests.rs b/crates/oxide_vm/tests/eval_script_global_tests.rs index 808ee9e4..5944cd29 100644 --- a/crates/oxide_vm/tests/eval_script_global_tests.rs +++ b/crates/oxide_vm/tests/eval_script_global_tests.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -12,6 +13,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -32,6 +34,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); vm.lookup_str(result).unwrap_or_else(|| format!("{result}")) } diff --git a/crates/oxide_vm/tests/eval_tests.rs b/crates/oxide_vm/tests/eval_tests.rs index e4996653..e68a88f4 100644 --- a/crates/oxide_vm/tests/eval_tests.rs +++ b/crates/oxide_vm/tests/eval_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::object::JsObject; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -21,6 +22,7 @@ fn assert_num(result: JsValue, expected: f64) { #[test] fn eval_string_expression_completion_value() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 脚本模式完成值保留:`eval('1+2')` 返回 3(档 2 起,不再被函数模式 body wrap 吞掉)。 let result = eval(&mut vm, "eval('1+2')").unwrap(); assert_num(result, 3.0); @@ -29,6 +31,7 @@ fn eval_string_expression_completion_value() { #[test] fn eval_string_number_completion_value() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 脚本模式完成值保留:`eval('42')` 返回 42。 let result = eval(&mut vm, "eval('42')").unwrap(); assert_num(result, 42.0); @@ -37,6 +40,7 @@ fn eval_string_number_completion_value() { #[test] fn eval_string_var_declaration_inside() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 档 2:eval 内 var 声明落全局对象,完成值保留为末表达式值。 let result = eval(&mut vm, "eval('var y = 1; y')").unwrap(); assert_num(result, 1.0); @@ -47,6 +51,7 @@ fn eval_string_var_declaration_inside() { #[test] fn eval_non_string_returns_as_is() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval(&mut vm, "eval(123)").unwrap(); assert_num(result, 123.0); } @@ -54,6 +59,7 @@ fn eval_non_string_returns_as_is() { #[test] fn eval_object_identity() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 非字符串实参原样返回:同一对象引用。 let result = eval(&mut vm, "var o = {}; eval(o) === o").unwrap(); assert_eq!(result, JsValue::bool(true)); @@ -62,6 +68,7 @@ fn eval_object_identity() { #[test] fn eval_new_string_not_tostring() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // new String 是非字符串对象:不 ToString,原样返回同一对象(非原始值)。 let result = eval(&mut vm, "var s = new String('1+1'); eval(s) === s").unwrap(); assert_eq!(result, JsValue::bool(true)); @@ -70,6 +77,7 @@ fn eval_new_string_not_tostring() { #[test] fn eval_throw_primitive_rethrown() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // eval 内 throw 1 重抛原始值 1,可被外层 catch 捕获(非 Error 包装)。 let result = eval(&mut vm, "try { eval('throw 1') } catch(e) { e }").unwrap(); assert_num(result, 1.0); @@ -78,6 +86,7 @@ fn eval_throw_primitive_rethrown() { #[test] fn eval_syntax_error_throws() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 换行分隔的 `x` 与 `++` 为非法语法,eval 抛 SyntaxError。 let result = eval(&mut vm, "try { eval('x\\u000A++') } catch(e) { e.name }").unwrap(); let rendered = vm.lookup_str(result).unwrap_or_default(); @@ -87,6 +96,7 @@ fn eval_syntax_error_throws() { #[test] fn eval_length_is_one() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval(&mut vm, "eval.length").unwrap(); assert_num(result, 1.0); } @@ -94,6 +104,7 @@ fn eval_length_is_one() { #[test] fn eval_name_is_eval() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval(&mut vm, "eval.name").unwrap(); let rendered = vm.lookup_str(result).unwrap_or_default(); assert_eq!(rendered, "eval"); @@ -102,6 +113,7 @@ fn eval_name_is_eval() { #[test] fn eval_global_descriptor() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 全局 eval 属性描述符:{writable:true, enumerable:false, configurable:true}。 let result = eval( &mut vm, @@ -115,6 +127,7 @@ fn eval_global_descriptor() { #[test] fn eval_new_throws_type_error() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // eval 不是构造器:new eval() 抛 TypeError。 let result = eval(&mut vm, "try { new eval() } catch(e) { e.name }").unwrap(); let rendered = vm.lookup_str(result).unwrap_or_default(); @@ -124,6 +137,7 @@ fn eval_new_throws_type_error() { #[test] fn eval_no_arg_and_undefined_are_undefined() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval(&mut vm, "eval() === undefined && eval(undefined) === undefined").unwrap(); assert_eq!(result, JsValue::bool(true)); } @@ -131,6 +145,7 @@ fn eval_no_arg_and_undefined_are_undefined() { #[test] fn eval_typeof_is_function() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval(&mut vm, "typeof eval").unwrap(); let rendered = vm.lookup_str(result).unwrap_or_default(); assert_eq!(rendered, "function"); @@ -139,6 +154,7 @@ fn eval_typeof_is_function() { #[test] fn eval_survives_full_reset_rebuild() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 仅 global 脏:full_reset 走 bind_global_functions 重建路径,eval 须保留。 let g_ptr = vm.session().global_object().as_ptr() as *mut JsObject; unsafe { (&mut *g_ptr).bump_generation() }; @@ -157,6 +173,7 @@ fn eval_survives_full_reset_rebuild() { #[test] fn eval_script_var_lands_on_global() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 间接 eval 脚本模式:var 声明落全局对象,外层 this 可见。 let result = eval(&mut vm, "(0,eval)('var q = 9'); this.q === 9").unwrap(); assert_eq!(result, JsValue::bool(true)); @@ -165,6 +182,7 @@ fn eval_script_var_lands_on_global() { #[test] fn eval_script_function_decl_lands_on_global() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 脚本模式:顶层函数声明落全局对象。 let result = eval(&mut vm, "(0,eval)('function f(){}'); typeof f === 'function'").unwrap(); assert_eq!(result, JsValue::bool(true)); @@ -173,6 +191,7 @@ fn eval_script_function_decl_lands_on_global() { #[test] fn eval_script_let_is_isolated() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // let/const 词法隔离:不落全局,不泄漏到外层。 let result = eval(&mut vm, "(0,eval)('let z = 1'); typeof z === 'undefined'").unwrap(); assert_eq!(result, JsValue::bool(true)); @@ -184,6 +203,7 @@ fn eval_script_let_is_isolated() { #[test] fn eval_script_this_is_global() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 脚本模式:this 与 globalThis 恒等(inline 调用 receiver 传 global)。 let result = eval(&mut vm, "(0,eval)('this === globalThis')").unwrap(); assert_eq!(result, JsValue::bool(true)); @@ -192,6 +212,7 @@ fn eval_script_this_is_global() { #[test] fn eval_nested_eval() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 嵌套 eval:内层完成值透传为外层脚本值。 let result = eval(&mut vm, "eval(\"eval('1+1')\")").unwrap(); assert_num(result, 2.0); @@ -200,6 +221,7 @@ fn eval_nested_eval() { #[test] fn eval_script_completion_value() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 间接 eval 脚本模式完成值:var 初始化 + 表达式。 let result = eval(&mut vm, "(0,eval)('var a = 1; a')").unwrap(); assert_num(result, 1.0); @@ -210,6 +232,7 @@ fn eval_script_completion_value() { #[test] fn eval_script_empty_and_decl_only() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 空脚本 / 纯声明脚本:完成值为 undefined。 let result = eval(&mut vm, "eval('') === undefined").unwrap(); assert_eq!(result, JsValue::bool(true)); @@ -220,6 +243,7 @@ fn eval_script_empty_and_decl_only() { #[test] fn eval_script_throw_still_rethrows() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 脚本模式异常路径回归:eval 内 throw 原始值,外层 catch 捕获同一值。 let result = eval(&mut vm, "try { (0,eval)('throw 5') } catch(e) { e }").unwrap(); assert_num(result, 5.0); @@ -228,6 +252,7 @@ fn eval_script_throw_still_rethrows() { #[test] fn compound_statement_completion_values() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // 混合形完成值:switch 命中 case 链最后非空值、无命中 undefined;空命中不沿用前值。 let result = eval(&mut vm, "7; switch(1){case 1: 9}").unwrap(); assert_num(result, 9.0); @@ -321,6 +346,7 @@ fn compound_statement_completion_values() { #[test] fn iteration_labeled_completion_values() { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); // do-while 循环体完成值 = 末次体值。 let result = eval(&mut vm, "7; do { 8 } while (false)").unwrap(); assert_num(result, 8.0); diff --git a/crates/oxide_vm/tests/for_head_lex_tests.rs b/crates/oxide_vm/tests/for_head_lex_tests.rs index ce88be7b..4201991a 100644 --- a/crates/oxide_vm/tests/for_head_lex_tests.rs +++ b/crates/oxide_vm/tests/for_head_lex_tests.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -22,6 +23,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/for_in_dstr_head_tdz_tests.rs b/crates/oxide_vm/tests/for_in_dstr_head_tdz_tests.rs index a913d9d2..41a2b9cd 100644 --- a/crates/oxide_vm/tests/for_in_dstr_head_tdz_tests.rs +++ b/crates/oxide_vm/tests/for_in_dstr_head_tdz_tests.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -21,6 +22,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/for_in_head_lex_tests.rs b/crates/oxide_vm/tests/for_in_head_lex_tests.rs index e51c8220..1b0a1c3f 100644 --- a/crates/oxide_vm/tests/for_in_head_lex_tests.rs +++ b/crates/oxide_vm/tests/for_in_head_lex_tests.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -21,6 +22,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/for_in_null_undefined_tests.rs b/crates/oxide_vm/tests/for_in_null_undefined_tests.rs index 06df57c2..fb7e3f16 100644 --- a/crates/oxide_vm/tests/for_in_null_undefined_tests.rs +++ b/crates/oxide_vm/tests/for_in_null_undefined_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/for_in_ordering_tests.rs b/crates/oxide_vm/tests/for_in_ordering_tests.rs index 6acc62f1..bf7eedd3 100644 --- a/crates/oxide_vm/tests/for_in_ordering_tests.rs +++ b/crates/oxide_vm/tests/for_in_ordering_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/for_in_var_head_fn_merge_tests.rs b/crates/oxide_vm/tests/for_in_var_head_fn_merge_tests.rs index a63d626f..605234f6 100644 --- a/crates/oxide_vm/tests/for_in_var_head_fn_merge_tests.rs +++ b/crates/oxide_vm/tests/for_in_var_head_fn_merge_tests.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -21,6 +22,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/for_of_abrupt_completion_tests.rs b/crates/oxide_vm/tests/for_of_abrupt_completion_tests.rs index c9d905d8..5e382fa6 100644 --- a/crates/oxide_vm/tests/for_of_abrupt_completion_tests.rs +++ b/crates/oxide_vm/tests/for_of_abrupt_completion_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/for_of_builtin_iter_tests.rs b/crates/oxide_vm/tests/for_of_builtin_iter_tests.rs index 542a712e..9b3a827c 100644 --- a/crates/oxide_vm/tests/for_of_builtin_iter_tests.rs +++ b/crates/oxide_vm/tests/for_of_builtin_iter_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/function_body_label_fn_tests.rs b/crates/oxide_vm/tests/function_body_label_fn_tests.rs index 8a5d530c..8d890a3b 100644 --- a/crates/oxide_vm/tests/function_body_label_fn_tests.rs +++ b/crates/oxide_vm/tests/function_body_label_fn_tests.rs @@ -10,6 +10,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -19,6 +20,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/function_length_tests.rs b/crates/oxide_vm/tests/function_length_tests.rs index 4684575e..39f26ea2 100644 --- a/crates/oxide_vm/tests/function_length_tests.rs +++ b/crates/oxide_vm/tests/function_length_tests.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use oxide_bytecode::module::CompiledModule; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -18,6 +19,7 @@ fn eval(source: &str) -> JsValue { fn run(module: &Arc) -> JsValue { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(module).expect("vm run failed") } @@ -26,6 +28,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse failed"); let module = Arc::new(Compiler::new().compile(&program).expect("compile failed")); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let v = vm.run(&module).expect("vm run failed"); // 字符串结果须在同一 VM 上读:perm 串指向 VM 私有内核,VM drop 后指针悬垂。 if v.is_string() { diff --git a/crates/oxide_vm/tests/generator_yield_star_tests.rs b/crates/oxide_vm/tests/generator_yield_star_tests.rs index 93ff1e85..0cc49b96 100644 --- a/crates/oxide_vm/tests/generator_yield_star_tests.rs +++ b/crates/oxide_vm/tests/generator_yield_star_tests.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -18,6 +19,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => { if result.is_string() { diff --git a/crates/oxide_vm/tests/global_builtin_constant_descriptor_tests.rs b/crates/oxide_vm/tests/global_builtin_constant_descriptor_tests.rs index 9f58b1f3..b388b172 100644 --- a/crates/oxide_vm/tests/global_builtin_constant_descriptor_tests.rs +++ b/crates/oxide_vm/tests/global_builtin_constant_descriptor_tests.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -19,12 +20,14 @@ fn compile(source: &str) -> oxide_bytecode::module::CompiledModule { fn run_truthy(source: &str) { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(compile(source))).expect("run"); assert!(result.is_bool() && result.as_bool(), "expected true, got: {result:?}\nsource: {source}"); } fn run_string(source: &str) -> String { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(compile(source))).expect("run"); if result.is_undefined() { return "undefined".to_string(); @@ -35,6 +38,7 @@ fn run_string(source: &str) -> String { /// 求值并返回完成值字符串;运行期异常返回错误文本(供 TypeError 断言)。 fn eval(source: &str) -> String { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(compile(source))) { Ok(result) => vm.lookup_str(result).unwrap_or_default(), Err(e) => e, diff --git a/crates/oxide_vm/tests/global_builtin_writable_tests.rs b/crates/oxide_vm/tests/global_builtin_writable_tests.rs index b31dca9d..a202250c 100644 --- a/crates/oxide_vm/tests/global_builtin_writable_tests.rs +++ b/crates/oxide_vm/tests/global_builtin_writable_tests.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -17,6 +18,7 @@ fn eval_truthy(source: &str) { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); assert!(result.is_bool() && result.as_bool(), "expected true, got: {result:?}\nsource: {source}"); } diff --git a/crates/oxide_vm/tests/global_fn_decl_builtin_tests.rs b/crates/oxide_vm/tests/global_fn_decl_builtin_tests.rs index 31015a67..486db428 100644 --- a/crates/oxide_vm/tests/global_fn_decl_builtin_tests.rs +++ b/crates/oxide_vm/tests/global_fn_decl_builtin_tests.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use oxide_bytecode::module::CompiledModule; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_emit::module::{ModuleSourceLoader, ResolvedModule}; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -17,6 +18,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -33,6 +35,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); vm.lookup_str(result).unwrap_or_else(|| format!("{result}")) } @@ -53,6 +56,7 @@ fn script_err_text(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Err(e) => e, Ok(v) => panic!("expected uncaught error, got: {v:?}\nsource: {source}"), @@ -68,6 +72,7 @@ fn err_then_script_str(decl: &str, probe: &str) -> String { Arc::new(Compiler::new().compile(&program).expect("compile")) }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let err = vm.run(&compile(decl)); assert!(err.is_err(), "声明脚本应抛未捕获异常,实际: {err:?}\ndecl: {decl}"); let result = vm.run(&compile(probe)).expect("probe run"); @@ -181,6 +186,7 @@ fn module_fn_decl_undefined_keeps_global_constant() { .compile_module(&program, "test.mjs", &mut NoopLoader) .expect("compile module"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)).expect("module run"); assert_eq!( diff --git a/crates/oxide_vm/tests/global_lexical_shadow_builtin_tests.rs b/crates/oxide_vm/tests/global_lexical_shadow_builtin_tests.rs index b53f88e8..2fb19b8f 100644 --- a/crates/oxide_vm/tests/global_lexical_shadow_builtin_tests.rs +++ b/crates/oxide_vm/tests/global_lexical_shadow_builtin_tests.rs @@ -10,6 +10,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_emit::module::{ModuleSourceLoader, ResolvedModule}; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -19,6 +20,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -60,6 +62,7 @@ fn eval_module(source: &str) -> Result { .compile_module(&program, "test.mjs", &mut Loader) .map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/global_mirror_sync_tests.rs b/crates/oxide_vm/tests/global_mirror_sync_tests.rs index 48bb1abd..253b1dae 100644 --- a/crates/oxide_vm/tests/global_mirror_sync_tests.rs +++ b/crates/oxide_vm/tests/global_mirror_sync_tests.rs @@ -12,6 +12,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -21,6 +22,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -29,6 +31,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); vm.lookup_str(result).unwrap_or_else(|| format!("{result}")) } diff --git a/crates/oxide_vm/tests/global_var_binding_tests.rs b/crates/oxide_vm/tests/global_var_binding_tests.rs index d82ff8ce..9dca3374 100644 --- a/crates/oxide_vm/tests/global_var_binding_tests.rs +++ b/crates/oxide_vm/tests/global_var_binding_tests.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -12,6 +13,7 @@ fn eval_truthy(source: &str) { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); assert!(result.is_bool() && result.as_bool(), "expected true, got: {result:?}\nsource: {source}"); } @@ -21,6 +23,7 @@ fn eval_string(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); vm.lookup_str(result).unwrap_or_default() } @@ -34,6 +37,7 @@ fn compile(source: &str) -> oxide_bytecode::module::CompiledModule { /// 两阶段执行:phase1 → `reset()`(轻量重置,epoch 清空、session 保留)→ phase2。 fn eval_two_phases(phase1: &str, phase2: &str) -> bool { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(compile(phase1))).expect("run1"); vm.reset(); let result = vm.run(&Arc::new(compile(phase2))).expect("run2"); @@ -43,6 +47,7 @@ fn eval_two_phases(phase1: &str, phase2: &str) -> bool { /// 两阶段 run-Err 变体:phase2 返回运行结果,供未捕获异常(TypeError 等)断言。 fn run_two_phases(phase1: &str, phase2: &str) -> Result { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(compile(phase1))).expect("run1"); vm.reset(); vm.run(&Arc::new(compile(phase2))) @@ -69,6 +74,7 @@ fn phase2_err_text(phase1: &str, phase2: &str) -> String { /// "true"/"false")。 fn phase2_err_then_probe(phase1: &str, phase2: &str, probe: &str) -> String { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(compile(phase1))).expect("run1"); vm.reset(); assert!(vm.run(&Arc::new(compile(phase2))).is_err(), "phase2 应抛未捕获异常: {phase2}"); @@ -576,6 +582,7 @@ fn strict_eval_var_init_on_nonwritable_user_property_throws() { fn nonextensible_global_strict_var_prologue_throws_before_body() { // 序言期抛:体副作用不执行(touched 未写入)。 let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(compile("Object.preventExtensions(globalThis)"))) .expect("run1"); vm.reset(); diff --git a/crates/oxide_vm/tests/implicit_global_write_tests.rs b/crates/oxide_vm/tests/implicit_global_write_tests.rs index fd01e5f5..2de38c2f 100644 --- a/crates/oxide_vm/tests/implicit_global_write_tests.rs +++ b/crates/oxide_vm/tests/implicit_global_write_tests.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -14,6 +15,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -34,6 +36,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); vm.lookup_str(result).unwrap_or_else(|| format!("{result}")) } diff --git a/crates/oxide_vm/tests/logical_tests.rs b/crates/oxide_vm/tests/logical_tests.rs index 9565e238..2c64450e 100644 --- a/crates/oxide_vm/tests/logical_tests.rs +++ b/crates/oxide_vm/tests/logical_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/loop_closure_binding_tests.rs b/crates/oxide_vm/tests/loop_closure_binding_tests.rs index 68b9a4d2..e4c9c3cb 100644 --- a/crates/oxide_vm/tests/loop_closure_binding_tests.rs +++ b/crates/oxide_vm/tests/loop_closure_binding_tests.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -12,6 +13,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } diff --git a/crates/oxide_vm/tests/object_tests.rs b/crates/oxide_vm/tests/object_tests.rs index 13b25dae..a5b0de1e 100644 --- a/crates/oxide_vm/tests/object_tests.rs +++ b/crates/oxide_vm/tests/object_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), @@ -28,6 +30,7 @@ fn object_create_and_read() { let program = oxide_parser::parse(&allocator, source).expect("parse failed"); let module = Compiler::new().compile(&program).expect("compile failed"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let obj = vm.run(&Arc::new(module)).expect("vm run failed"); assert!(obj.is_object()); let obj_ref = unsafe { &*obj.as_js_object_ptr() }; @@ -273,6 +276,7 @@ fn object_literal_getter_setter_pair() { fn eval_string(source: &str) -> String { let allocator = Allocator::default(); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let program = oxide_parser::parse(&allocator, source).expect("parse failed"); let module = Compiler::new().compile(&program).expect("compile failed"); let result = vm.run(&Arc::new(module)).expect("vm run failed"); diff --git a/crates/oxide_vm/tests/property_keys_order_tests.rs b/crates/oxide_vm/tests/property_keys_order_tests.rs index 28f67316..4f737ae3 100644 --- a/crates/oxide_vm/tests/property_keys_order_tests.rs +++ b/crates/oxide_vm/tests/property_keys_order_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -9,6 +10,7 @@ fn eval(source: &str) -> Result<(Vm, JsValue), String> { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } diff --git a/crates/oxide_vm/tests/proto_chain_tests.rs b/crates/oxide_vm/tests/proto_chain_tests.rs index 89e1e21d..8920c0c9 100644 --- a/crates/oxide_vm/tests/proto_chain_tests.rs +++ b/crates/oxide_vm/tests/proto_chain_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -9,6 +10,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/readonly_global_builtin_tests.rs b/crates/oxide_vm/tests/readonly_global_builtin_tests.rs index aa137df9..e6e75ffa 100644 --- a/crates/oxide_vm/tests/readonly_global_builtin_tests.rs +++ b/crates/oxide_vm/tests/readonly_global_builtin_tests.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -16,6 +17,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -36,6 +38,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); vm.lookup_str(result).unwrap_or_else(|| format!("{result}")) } diff --git a/crates/oxide_vm/tests/regression_tests.rs b/crates/oxide_vm/tests/regression_tests.rs index 02571f31..781d4e5f 100644 --- a/crates/oxide_vm/tests/regression_tests.rs +++ b/crates/oxide_vm/tests/regression_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_kernel::kernel::{KernelConfig, KernelCore}; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -16,6 +17,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), @@ -33,6 +35,7 @@ fn eval_with_kernel(source: &str, kernel: Arc) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::with_kernel_core(kernel); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), @@ -52,6 +55,7 @@ fn regression_rerun_clears_ic_cache() { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); assert_eq!(format!("{}", vm.run(&Arc::new(module)).unwrap()), "1"); let source2 = "var o = {a: 2}; o.a"; @@ -188,6 +192,7 @@ fn eval_shallow(source: &str, depth: usize) -> String { let mut cfg = KernelConfig::minimal(); cfg.max_call_depth = depth; let mut vm = Vm::with_kernel_core(KernelCore::new(cfg)); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(val) => { if val.is_string() { diff --git a/crates/oxide_vm/tests/rest_params_tests.rs b/crates/oxide_vm/tests/rest_params_tests.rs index 1f0050f7..b1156550 100644 --- a/crates/oxide_vm/tests/rest_params_tests.rs +++ b/crates/oxide_vm/tests/rest_params_tests.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -13,6 +14,7 @@ fn eval(source: &str) -> JsValue { let program = oxide_parser::parse(&allocator, source).expect("parse failed"); let module = Compiler::new().compile(&program).expect("compile failed"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)).expect("vm run failed") } @@ -32,6 +34,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse failed"); let module = Compiler::new().compile(&program).expect("compile failed"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let v = vm.run(&Arc::new(module)).expect("vm run failed"); // 字符串结果须在同一 VM 上读:perm 串指向 VM 私有内核,VM drop 后指针悬垂。 if v.is_string() { diff --git a/crates/oxide_vm/tests/scoping_tests.rs b/crates/oxide_vm/tests/scoping_tests.rs index 9edcf692..223e6b8c 100644 --- a/crates/oxide_vm/tests/scoping_tests.rs +++ b/crates/oxide_vm/tests/scoping_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -9,6 +10,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/si0_prototype_key_tests.rs b/crates/oxide_vm/tests/si0_prototype_key_tests.rs index be8ca420..c673a4ce 100644 --- a/crates/oxide_vm/tests/si0_prototype_key_tests.rs +++ b/crates/oxide_vm/tests/si0_prototype_key_tests.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -24,6 +25,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => js_value_to_str(result), Err(e) => format!("vm error: {e}"), @@ -41,6 +43,7 @@ fn eval_json(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => js_value_to_str(result), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/sloppy_assignment_silent_tests.rs b/crates/oxide_vm/tests/sloppy_assignment_silent_tests.rs index f783a54c..51e68c21 100644 --- a/crates/oxide_vm/tests/sloppy_assignment_silent_tests.rs +++ b/crates/oxide_vm/tests/sloppy_assignment_silent_tests.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -14,6 +15,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -34,6 +36,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run"); vm.lookup_str(result).unwrap_or_else(|| format!("{result}")) } diff --git a/crates/oxide_vm/tests/switch_case_fn_tests.rs b/crates/oxide_vm/tests/switch_case_fn_tests.rs index bbff33c3..6937ee73 100644 --- a/crates/oxide_vm/tests/switch_case_fn_tests.rs +++ b/crates/oxide_vm/tests/switch_case_fn_tests.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -17,6 +18,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/switch_default_tests.rs b/crates/oxide_vm/tests/switch_default_tests.rs index e56d1356..7de84e3f 100644 --- a/crates/oxide_vm/tests/switch_default_tests.rs +++ b/crates/oxide_vm/tests/switch_default_tests.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } @@ -24,6 +26,7 @@ fn eval_str(source: &str) -> String { let program = oxide_parser::parse(&allocator, source).expect("parse"); let module = Compiler::new().compile(&program).expect("compile"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let value = vm.run(&Arc::new(module)).expect("run"); assert!(value.is_string(), "expected string, got {value:?}"); // SAFETY: is_string 已确认值为字符串指针,内容在 VM 析构前拷贝为自有 String。 diff --git a/crates/oxide_vm/tests/tdz_named_message_tests.rs b/crates/oxide_vm/tests/tdz_named_message_tests.rs index ceee9f65..e3e355e5 100644 --- a/crates/oxide_vm/tests/tdz_named_message_tests.rs +++ b/crates/oxide_vm/tests/tdz_named_message_tests.rs @@ -11,6 +11,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_vm::vm::Vm; fn eval(source: &str) -> Result { @@ -18,6 +19,7 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("parse error: {}", e[0].message))?; let module = Compiler::new().compile(&program).map_err(|e| format!("compile error: {e}"))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } diff --git a/crates/oxide_vm/tests/tdz_upvalue_capture_tests.rs b/crates/oxide_vm/tests/tdz_upvalue_capture_tests.rs index 48ab1df0..80351f2b 100644 --- a/crates/oxide_vm/tests/tdz_upvalue_capture_tests.rs +++ b/crates/oxide_vm/tests/tdz_upvalue_capture_tests.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -23,6 +24,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/template_tests.rs b/crates/oxide_vm/tests/template_tests.rs index 3d16d559..51bd2e2d 100644 --- a/crates/oxide_vm/tests/template_tests.rs +++ b/crates/oxide_vm/tests/template_tests.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use oxide_bytecode::module::Constant; use oxide_bytecode::opcode::OpCode; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_ir::inst::Inst; use oxide_ir::operand::Operand; use oxide_ir::IRFunction; @@ -21,6 +22,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {}", e), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{}", result), Err(e) => format!("vm error: {}", e), @@ -38,6 +40,7 @@ fn eval_val(source: &str) -> (Vm, Result) { Err(e) => return (Vm::new(), Err(format!("compile error: {}", e))), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)); (vm, result) } @@ -136,6 +139,7 @@ fn template_expression_reads_physical_register_above_127() { let module = oxide_ir::lower::lower(&ir).expect("lower template IR"); let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = vm.run(&Arc::new(module)).expect("run template IR"); assert_eq!(to_str(&vm, result), "value"); } diff --git a/crates/oxide_vm/tests/test262_host_tests.rs b/crates/oxide_vm/tests/test262_host_tests.rs index 14da0b50..9fe32a64 100644 --- a/crates/oxide_vm/tests/test262_host_tests.rs +++ b/crates/oxide_vm/tests/test262_host_tests.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_kernel::kernel::{KernelConfig, KernelCore}; use oxide_parser::Allocator; use oxide_types::value::JsValue; @@ -21,6 +22,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => vm.lookup_str(result).unwrap_or_else(|| format!("{result}")), Err(e) => format!("vm error: {e}"), @@ -104,6 +106,7 @@ fn gc_keeps_reachable_session_objects_alive() { let mut config = KernelConfig::minimal(); config.set_session_gc_threshold(4096); let mut vm = Vm::with_kernel_core(KernelCore::new(config)); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let result = eval_on( &mut vm, "(function () { \ diff --git a/crates/oxide_vm/tests/try_finally_control_flow_tests.rs b/crates/oxide_vm/tests/try_finally_control_flow_tests.rs index ac9b1025..c92c0fbe 100644 --- a/crates/oxide_vm/tests/try_finally_control_flow_tests.rs +++ b/crates/oxide_vm/tests/try_finally_control_flow_tests.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -21,6 +22,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/undeclared_read_tests.rs b/crates/oxide_vm/tests/undeclared_read_tests.rs index 912be587..d74aa780 100644 --- a/crates/oxide_vm/tests/undeclared_read_tests.rs +++ b/crates/oxide_vm/tests/undeclared_read_tests.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; @@ -14,12 +15,14 @@ fn eval(source: &str) -> Result { let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); vm.run(&Arc::new(module)) } /// 求值并取字符串结果内容(字符串值走 lookup_str,非字符串走 Display)。 fn eval_str(source: &str) -> Result { let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); let allocator = oxide_parser::Allocator::default(); let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?; diff --git a/crates/oxide_vm/tests/update_tests.rs b/crates/oxide_vm/tests/update_tests.rs index 1a23b033..832390d4 100644 --- a/crates/oxide_vm/tests/update_tests.rs +++ b/crates/oxide_vm/tests/update_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/var_binding_tests.rs b/crates/oxide_vm/tests/var_binding_tests.rs index 99d674f6..5266f21b 100644 --- a/crates/oxide_vm/tests/var_binding_tests.rs +++ b/crates/oxide_vm/tests/var_binding_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), diff --git a/crates/oxide_vm/tests/vm_tests.rs b/crates/oxide_vm/tests/vm_tests.rs index 4e2d53af..ca3f3227 100644 --- a/crates/oxide_vm/tests/vm_tests.rs +++ b/crates/oxide_vm/tests/vm_tests.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use oxide_compiler::compiler::Compiler; +use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; @@ -15,6 +16,7 @@ fn eval(source: &str) -> String { Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); + vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"),