mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
refactor: 动态编译改经 CompilerService 注入,oxide_vm 去编译器依赖
This commit is contained in:
Generated
+20
-18
@@ -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",
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.68"
|
||||
version = "0.8.69"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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<KernelCore>) -> 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<KernelCore>) -> 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<KernelCore>) -> 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<KernelCore>) -> 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<KernelCore>) -> 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);
|
||||
|
||||
@@ -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<KernelCore> {
|
||||
}
|
||||
|
||||
fn make_pool(kernel: &Arc<KernelCore>) -> Arc<VmPool> {
|
||||
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 {
|
||||
|
||||
@@ -100,12 +100,13 @@ fn panic_payload_str(payload: &Box<dyn std::any::Any + Send>) -> String {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use oxide_compiler::DefaultCompilerService;
|
||||
use oxide_kernel::kernel::KernelConfig;
|
||||
|
||||
/// 测试环境:minimal 内核加单 VM 池(与池既有测试同口径)。
|
||||
fn test_env() -> (Arc<KernelCore>, Arc<VmPool>) {
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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<KernelCore>, Arc<VmPool>) {
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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<dyn CompilerService>` 可跨线程共享。
|
||||
pub struct DefaultCompilerService;
|
||||
|
||||
impl CompilerService for DefaultCompilerService {
|
||||
fn compile_script(&self, source: &str) -> Result<CompiledModule, String> {
|
||||
// 局部分配器: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<CompiledModule, String> {
|
||||
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<Program<'a>, String> {
|
||||
oxide_parser::parse(allocator, source)
|
||||
.map_err(|errs| errs.into_iter().map(|e| e.message).collect::<Vec<_>>().join("\n"))
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//! 动态编译服务接口:`Vm` 经它把源码编译为 `CompiledModule`,
|
||||
//! 解耦 `oxide_vm` 对 `oxide_compiler` / `oxide_parser` 的直接依赖。
|
||||
|
||||
use oxide_bytecode::module::CompiledModule;
|
||||
|
||||
/// 动态编译服务:`Vm` 经它把源码编译为 `CompiledModule`。
|
||||
///
|
||||
/// 无状态实现 `Send + Sync`,`Arc<dyn CompilerService>` 可跨线程共享
|
||||
/// (worker 调度、多 realm 场景)。trait 对象安全,`Vm` 以
|
||||
/// `Arc<dyn CompilerService>` 持服务句柄。
|
||||
pub trait CompilerService: Send + Sync {
|
||||
/// 编译普通脚本(source_encoded 形态),返回完整模块树
|
||||
/// (根 flat_id=0 + 子模块)。
|
||||
///
|
||||
/// 供 `Function` 构造器(wrap 源码)与 `$262.evalScript`(普通脚本)。
|
||||
fn compile_script(&self, source: &str) -> Result<CompiledModule, String>;
|
||||
|
||||
/// 编译 eval 脚本(source_encoded + eval_script 形态),返回完整模块树。
|
||||
///
|
||||
/// 顶层 var/function 声明落全局属性 configurable:true。
|
||||
fn compile_eval_script(&self, source: &str) -> Result<CompiledModule, String>;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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]]
|
||||
|
||||
@@ -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<CompiledModule, String> {
|
||||
Err("dynamic compilation unavailable: no compiler service installed".to_string())
|
||||
}
|
||||
|
||||
fn compile_eval_script(&self, _source: &str) -> Result<CompiledModule, String> {
|
||||
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::<Vec<_>>().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<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse(&allocator, code)
|
||||
.map_err(|errs| errs.into_iter().map(|e| e.message).collect::<Vec<_>>().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<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse(&allocator, code)
|
||||
.map_err(|errs| errs.into_iter().map(|e| e.message).collect::<Vec<_>>().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();
|
||||
|
||||
@@ -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<KernelCore>,
|
||||
/// 动态编译服务句柄:`Function` 构造器 / eval / `$262.evalScript` 经它编译
|
||||
/// 源码(`dynamic.rs` 三方法)。缺省为 no-op stub(返 `Err`),生产 entry
|
||||
/// points 与动态编译测试经 `set_compiler_service` 注入真实实现。
|
||||
/// `Arc<dyn CompilerService>` 因 trait `Send + Sync` 而 Send + Sync,
|
||||
/// 不破坏 `unsafe impl Send for Vm`。
|
||||
pub(crate) compiler: Arc<dyn oxide_runtime_api::CompilerService>,
|
||||
/// 每 VM 的 realm 组合:内核会话(builtin world 与 global 对象)、
|
||||
/// session GC 簿记与 10 个内建原型槽(见 `realm` 模块)。以 `Arc` 持有:
|
||||
/// 可变组经 `RefCell` 内部可变性在 `&Arc<Realm>` 下改写,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<dyn oxide_runtime_api::CompilerService>) {
|
||||
self.compiler = service;
|
||||
}
|
||||
|
||||
/// 只读访问当前 session(builtin world 与 global object)。
|
||||
///
|
||||
/// 返回 `Ref` 守卫(session 入 `RefCell` 后无法再给稳定 `&`):调用方
|
||||
|
||||
@@ -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<Vm>,
|
||||
@@ -74,6 +75,9 @@ impl PoolCounters {
|
||||
/// 归还(带 5 秒超时强制扩容兜底)。线程安全,可供多线程并发领取。
|
||||
pub struct VmPool {
|
||||
kernel_core: Arc<KernelCore>,
|
||||
/// 动态编译服务句柄:构造期定、此后不可变,`new_vm` 逐个注入每个 Vm
|
||||
/// (预热与增长路径同口径,无「预热后补注入」时序问题)。
|
||||
compiler: Arc<dyn CompilerService>,
|
||||
inner: Mutex<VmPoolInner>,
|
||||
condvar: Condvar,
|
||||
max_size: Option<usize>,
|
||||
@@ -94,9 +98,12 @@ impl VmPool {
|
||||
/// 创建 VM 池并同步预热 `min_size` 个 Vm(数量受 `max_size` 钳制),
|
||||
/// 首次 `spawn` 直接命中池。`max_size` 为池上限,`None` 表示不限。
|
||||
///
|
||||
/// `compiler` 为池内全部 Vm 的动态编译服务(构造期定、此后不可变)。
|
||||
/// 计数器为本池私有(不与其他池共享)。
|
||||
pub fn new(kernel_core: Arc<KernelCore>, min_size: usize, max_size: Option<usize>) -> Arc<Self> {
|
||||
Self::with_counters(kernel_core, min_size, max_size, PoolCounters::shared())
|
||||
pub fn new(
|
||||
kernel_core: Arc<KernelCore>, compiler: Arc<dyn CompilerService>, min_size: usize, max_size: Option<usize>,
|
||||
) -> Arc<Self> {
|
||||
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<KernelCore>, min_size: usize, max_size: Option<usize>, counters: Arc<PoolCounters>,
|
||||
kernel_core: Arc<KernelCore>, compiler: Arc<dyn CompilerService>, min_size: usize, max_size: Option<usize>,
|
||||
counters: Arc<PoolCounters>,
|
||||
) -> Arc<Self> {
|
||||
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<KernelCore>) -> 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> {
|
||||
KernelCore::new(KernelConfig::minimal())
|
||||
}
|
||||
|
||||
/// 测试池的编译服务(池测试不 exercise 动态编译,缺省实现即可)。
|
||||
fn test_compiler() -> Arc<dyn CompilerService> {
|
||||
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");
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<JsValue, String>) {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
|
||||
@@ -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 }",
|
||||
|
||||
@@ -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<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));
|
||||
vm.run(&Arc::new(module))
|
||||
}
|
||||
|
||||
@@ -18,6 +20,7 @@ fn eval_with_vm(source: &str) -> (Vm, Result<JsValue, 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));
|
||||
(vm, result)
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
@@ -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<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));
|
||||
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}"))
|
||||
}
|
||||
|
||||
@@ -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<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));
|
||||
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}"))
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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<CompiledModule>) -> 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() {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
@@ -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<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));
|
||||
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!(
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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<JsValue, String> {
|
||||
.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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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<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));
|
||||
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}"))
|
||||
}
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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();
|
||||
|
||||
@@ -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<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));
|
||||
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}"))
|
||||
}
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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<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));
|
||||
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}"))
|
||||
}
|
||||
|
||||
@@ -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<KernelCore>) -> 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() {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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<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));
|
||||
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}"))
|
||||
}
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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。
|
||||
|
||||
@@ -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<oxide_types::value::JsValue, String> {
|
||||
@@ -18,6 +19,7 @@ fn eval(source: &str) -> Result<oxide_types::value::JsValue, String> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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<JsValue, String>) {
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -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 () { \
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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<JsValue, String> {
|
||||
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<String, String> {
|
||||
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))?;
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
Reference in New Issue
Block a user