mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: 解析入口改用线程本地分配器,稳态免系统调用
This commit is contained in:
Generated
+20
-20
@@ -1160,7 +1160,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_builtins"
|
name = "oxide_builtins"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"fast-float",
|
"fast-float",
|
||||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_bytecode"
|
name = "oxide_bytecode"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cfg"
|
name = "oxide_cfg"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_emit",
|
"oxide_emit",
|
||||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cli"
|
name = "oxide_cli"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
@@ -1228,7 +1228,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_code_cache"
|
name = "oxide_code_cache"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lru",
|
"lru",
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
@@ -1237,7 +1237,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_compiler"
|
name = "oxide_compiler"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1257,7 +1257,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_dce"
|
name = "oxide_dce"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1271,7 +1271,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_emit"
|
name = "oxide_emit"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
@@ -1286,7 +1286,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_engine"
|
name = "oxide_engine"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1298,7 +1298,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_ir"
|
name = "oxide_ir"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1307,7 +1307,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_kernel"
|
name = "oxide_kernel"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_liveness"
|
name = "oxide_liveness"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1333,7 +1333,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_log"
|
name = "oxide_log"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-appender",
|
"tracing-appender",
|
||||||
@@ -1342,11 +1342,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_net"
|
name = "oxide_net"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_parser"
|
name = "oxide_parser"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
"oxc_ast",
|
"oxc_ast",
|
||||||
@@ -1361,7 +1361,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_regalloc"
|
name = "oxide_regalloc"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1377,7 +1377,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_runtime_api"
|
name = "oxide_runtime_api"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -1390,7 +1390,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_test262"
|
name = "oxide_test262"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1410,7 +1410,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_types"
|
name = "oxide_types"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1423,7 +1423,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_vm"
|
name = "oxide_vm"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
rust-version = "1.80"
|
rust-version = "1.80"
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use oxide_compiler::compiler::{compiled_module_hash, Compiler};
|
use oxide_compiler::compiler::{compiled_module_hash, Compiler};
|
||||||
use oxide_kernel::kernel::KernelCore;
|
use oxide_kernel::kernel::KernelCore;
|
||||||
use oxide_parser::Allocator;
|
|
||||||
use oxide_vm::vm_pool::VmPool;
|
use oxide_vm::vm_pool::VmPool;
|
||||||
|
|
||||||
use super::protocol::ServerResponse;
|
use super::protocol::ServerResponse;
|
||||||
@@ -20,7 +19,7 @@ use super::protocol::ServerResponse;
|
|||||||
/// 执行请求处理:解析 → 编译 → 取 VM → 执行 → 渲染完成值 → 归还池的六段路径。
|
/// 执行请求处理:解析 → 编译 → 取 VM → 执行 → 渲染完成值 → 归还池的六段路径。
|
||||||
///
|
///
|
||||||
/// # 步骤
|
/// # 步骤
|
||||||
/// 1. parse:局部分配器加 `oxide_parser::parse`,失败时各条错误换行拼接成错误帧。
|
/// 1. parse:线程本地分配器加 `oxide_parser::parse`,失败时各条错误换行拼接成错误帧。
|
||||||
/// 2. compile:`Compiler` 加 `CodeForge` 结构哈希缓存,失败以原文成错误帧。
|
/// 2. compile:`Compiler` 加 `CodeForge` 结构哈希缓存,失败以原文成错误帧。
|
||||||
/// 3. spawn:从池取 `VmGuard`(闭包内创建,panic 时随展开被 drop)。
|
/// 3. spawn:从池取 `VmGuard`(闭包内创建,panic 时随展开被 drop)。
|
||||||
/// 4. run:设每请求步数覆盖(含 None)后 `run`,`Err` 即错误帧。
|
/// 4. run:设每请求步数覆盖(含 None)后 `run`,`Err` 即错误帧。
|
||||||
@@ -38,22 +37,22 @@ use super::protocol::ServerResponse;
|
|||||||
/// - release 下 `panic=abort` 使 `catch_unwind` 空操作,watchdog 是崩溃后恢复的唯一自动手段。
|
/// - release 下 `panic=abort` 使 `catch_unwind` 空操作,watchdog 是崩溃后恢复的唯一自动手段。
|
||||||
pub fn handle_eval(code: &str, max_steps: Option<u64>, kernel: &Arc<KernelCore>, pool: &Arc<VmPool>) -> ServerResponse {
|
pub fn handle_eval(code: &str, max_steps: Option<u64>, kernel: &Arc<KernelCore>, pool: &Arc<VmPool>) -> ServerResponse {
|
||||||
let response = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
let response = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||||
// parse:局部分配器,解析失败各条换行拼接成错误帧。
|
// parse + compile:线程本地分配器,AST 生命周期被闭包边界约束(不逃逸)。
|
||||||
let allocator = Allocator::default();
|
// 解析失败各条换行拼接成错误帧,编译失败以原文成错误帧。
|
||||||
let program = match oxide_parser::parse(&allocator, code) {
|
let module = match oxide_parser::with_parse_allocator(|allocator| {
|
||||||
Ok(program) => program,
|
let program = oxide_parser::parse(allocator, code).map_err(|errors| {
|
||||||
Err(errors) => {
|
|
||||||
let message = errors.iter().map(|e| e.to_string()).collect::<Vec<_>>().join("\n");
|
let message = errors.iter().map(|e| e.to_string()).collect::<Vec<_>>().join("\n");
|
||||||
return ServerResponse::eval_err(message);
|
ServerResponse::eval_err(message)
|
||||||
}
|
})?;
|
||||||
};
|
let compiler = Compiler::new();
|
||||||
|
let hash = compiled_module_hash(&program);
|
||||||
// compile:结构哈希缓存,失败以原文成错误帧。
|
kernel
|
||||||
let compiler = Compiler::new();
|
.code_forge()
|
||||||
let hash = compiled_module_hash(&program);
|
.get_or_insert_with(hash, || compiler.compile(&program))
|
||||||
let module = match kernel.code_forge().get_or_insert_with(hash, || compiler.compile(&program)) {
|
.map_err(ServerResponse::eval_err)
|
||||||
|
}) {
|
||||||
Ok(module) => module,
|
Ok(module) => module,
|
||||||
Err(message) => return ServerResponse::eval_err(message),
|
Err(response) => return response,
|
||||||
};
|
};
|
||||||
|
|
||||||
// spawn:从池取 VM;guard 在闭包内创建,panic 时随展开被 drop。
|
// spawn:从池取 VM;guard 在闭包内创建,panic 时随展开被 drop。
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//! 默认编译服务:串联 `oxide_parser::parse` 与 `Compiler::compile`,
|
//! 默认编译服务:串联 `oxide_parser::parse` 与 `Compiler::compile`,
|
||||||
//! parse 错误映射与 `Allocator` 构造的唯一实现源。
|
//! parse 错误映射的唯一实现源。
|
||||||
|
|
||||||
use oxide_bytecode::module::CompiledModule;
|
use oxide_bytecode::module::CompiledModule;
|
||||||
use oxide_parser::Program;
|
use oxide_parser::Program;
|
||||||
@@ -13,22 +13,24 @@ pub struct DefaultCompilerService;
|
|||||||
|
|
||||||
impl CompilerService for DefaultCompilerService {
|
impl CompilerService for DefaultCompilerService {
|
||||||
fn compile_script(&self, source: &str) -> Result<CompiledModule, String> {
|
fn compile_script(&self, source: &str) -> Result<CompiledModule, String> {
|
||||||
// 局部分配器:AST 节点经 oxc bump 分配器分配,编译完成即弃。
|
// 线程本地分配器:AST 节点经 oxc bump 分配器分配,编译完成即弃。
|
||||||
let allocator = oxide_parser::Allocator::default();
|
oxide_parser::with_parse_allocator(|allocator| {
|
||||||
let program = parse_program(&allocator, source)?;
|
let program = parse_program(allocator, source)?;
|
||||||
// 动态路径源契约:调用方以源码域转义(`string_forge::source_escape`)
|
// 动态路径源契约:调用方以源码域转义(`string_forge::source_escape`)
|
||||||
// 形态传源,故置 source_encoded。
|
// 形态传源,故置 source_encoded。
|
||||||
Compiler::new().with_source_encoded(true).compile(&program)
|
Compiler::new().with_source_encoded(true).compile(&program)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_eval_script(&self, source: &str) -> Result<CompiledModule, String> {
|
fn compile_eval_script(&self, source: &str) -> Result<CompiledModule, String> {
|
||||||
let allocator = oxide_parser::Allocator::default();
|
oxide_parser::with_parse_allocator(|allocator| {
|
||||||
let program = parse_program(&allocator, source)?;
|
let program = parse_program(allocator, source)?;
|
||||||
// eval 脚本:顶层 var/function 声明落全局属性 configurable:true。
|
// eval 脚本:顶层 var/function 声明落全局属性 configurable:true。
|
||||||
Compiler::new()
|
Compiler::new()
|
||||||
.with_eval_script(true)
|
.with_eval_script(true)
|
||||||
.with_source_encoded(true)
|
.with_source_encoded(true)
|
||||||
.compile(&program)
|
.compile(&program)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -958,27 +958,30 @@ impl Emitter {
|
|||||||
fn compile_js_dep(
|
fn compile_js_dep(
|
||||||
&self, resolved: &ResolvedModule, loader: &mut dyn ModuleSourceLoader, path_stack: &mut Vec<String>,
|
&self, resolved: &ResolvedModule, loader: &mut dyn ModuleSourceLoader, path_stack: &mut Vec<String>,
|
||||||
) -> Result<(IRFunction, bool, HashSet<String>, HashSet<String>), String> {
|
) -> Result<(IRFunction, bool, HashSet<String>, HashSet<String>), String> {
|
||||||
let alloc = oxide_parser::Allocator::default();
|
// 线程本地分配器:依赖模块递归解析共享同一分配器,
|
||||||
let program = oxide_parser::parse_module(&alloc, &resolved.source).map_err(|errs| {
|
// 重入深度守卫防止嵌套 reset 销毁外层 AST。
|
||||||
format!(
|
oxide_parser::with_parse_allocator(|alloc| {
|
||||||
"module parse error: {}",
|
let program = oxide_parser::parse_module(alloc, &resolved.source).map_err(|errs| {
|
||||||
errs.first().map(|e| e.message.as_str()).unwrap_or("parse failed")
|
format!(
|
||||||
)
|
"module parse error: {}",
|
||||||
})?;
|
errs.first().map(|e| e.message.as_str()).unwrap_or("parse failed")
|
||||||
let mut ctx = CompileCtx::new();
|
)
|
||||||
ctx.is_global_scope = false;
|
})?;
|
||||||
// 依赖模块经 parse_module 解析,顶层恒严格模式。
|
let mut ctx = CompileCtx::new();
|
||||||
ctx.is_strict = true;
|
ctx.is_global_scope = false;
|
||||||
self.emit_module_into_ctx(&program, &resolved.path, loader, path_stack, &mut ctx, false)?;
|
// 依赖模块经 parse_module 解析,顶层恒严格模式。
|
||||||
let reassignable = ctx.module_live_dep;
|
ctx.is_strict = true;
|
||||||
let own_export_names = module_own_export_names(&program.body);
|
self.emit_module_into_ctx(&program, &resolved.path, loader, path_stack, &mut ctx, false)?;
|
||||||
let var_scoped = module_var_scoped_export_names(&program.body);
|
let reassignable = ctx.module_live_dep;
|
||||||
Ok((
|
let own_export_names = module_own_export_names(&program.body);
|
||||||
ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None),
|
let var_scoped = module_var_scoped_export_names(&program.body);
|
||||||
reassignable,
|
Ok((
|
||||||
own_export_names,
|
ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None),
|
||||||
var_scoped,
|
reassignable,
|
||||||
))
|
own_export_names,
|
||||||
|
var_scoped,
|
||||||
|
))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 发 defer 预注册:对 deferred namespace 对象逐名 `__modulePreRegister`,
|
/// 发 defer 预注册:对 deferred namespace 对象逐名 `__modulePreRegister`,
|
||||||
|
|||||||
@@ -68,16 +68,16 @@ impl Engine {
|
|||||||
/// 构造传入,无缺省臂,漏传即旗标失效。
|
/// 构造传入,无缺省臂,漏传即旗标失效。
|
||||||
///
|
///
|
||||||
/// # 步骤
|
/// # 步骤
|
||||||
/// 1. 局部分配器上解析源码为 Program。
|
/// 1. 线程本地分配器上解析源码为 Program。
|
||||||
/// 2. 结构哈希作缓存键,CodeForge 未命中时调给定编译器编译并缓存。
|
/// 2. 结构哈希作缓存键,CodeForge 未命中时调给定编译器编译并缓存。
|
||||||
pub fn compile_with(&self, source: &str, compiler: &Compiler) -> Result<Arc<CompiledModule>, String> {
|
pub fn compile_with(&self, source: &str, compiler: &Compiler) -> Result<Arc<CompiledModule>, String> {
|
||||||
// 局部分配器:AST 节点经 oxc bump 分配器分配,编译完成即弃。
|
oxide_parser::with_parse_allocator(|allocator| {
|
||||||
let allocator = oxide_parser::Allocator::default();
|
let program = oxide_parser::parse(allocator, source)
|
||||||
let program = oxide_parser::parse(&allocator, source)
|
.map_err(|errs| errs.into_iter().map(|e| e.message).collect::<Vec<_>>().join("\n"))?;
|
||||||
.map_err(|errs| errs.into_iter().map(|e| e.message).collect::<Vec<_>>().join("\n"))?;
|
|
||||||
|
|
||||||
let hash = compiled_module_hash(&program);
|
let hash = compiled_module_hash(&program);
|
||||||
self.kernel.code_forge().get_or_insert_with(hash, || compiler.compile(&program))
|
self.kernel.code_forge().get_or_insert_with(hash, || compiler.compile(&program))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 编译 + 池借出 Vm 执行,返回完成值(eval 便捷路径)。
|
/// 编译 + 池借出 Vm 执行,返回完成值(eval 便捷路径)。
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ mod error;
|
|||||||
mod parser_log;
|
mod parser_log;
|
||||||
mod redeclaration_filter;
|
mod redeclaration_filter;
|
||||||
|
|
||||||
|
use std::cell::{Cell, UnsafeCell};
|
||||||
|
|
||||||
/// 解析错误:消息 + 源文件字节区间(起始,结束)。
|
/// 解析错误:消息 + 源文件字节区间(起始,结束)。
|
||||||
pub use error::OxideError;
|
pub use error::OxideError;
|
||||||
/// 重导出 `oxc_allocator::Allocator`:AST 节点的 bump 分配器,解析产物生命周期由其决定。
|
/// 重导出 `oxc_allocator::Allocator`:AST 节点的 bump 分配器,解析产物生命周期由其决定。
|
||||||
@@ -13,6 +15,59 @@ pub use oxc_ast::ast::*;
|
|||||||
/// 重导出 `oxc_span::Span`:源码中的位置区间。
|
/// 重导出 `oxc_span::Span`:源码中的位置区间。
|
||||||
pub use oxc_span::Span;
|
pub use oxc_span::Span;
|
||||||
|
|
||||||
|
// 线程本地持久 bump 分配器:解析入口共享该分配器,chunk 内存按线程
|
||||||
|
// 高水位保留复用,稳态解析不再走全局分配器。
|
||||||
|
//
|
||||||
|
// 分配器存于 `UnsafeCell`:唯一可变操作 `reset()` 只在最外层(深度为零)
|
||||||
|
// 调用,彼时尚无共享引用存活;闭包执行期间只产生共享 `&Allocator` 引用
|
||||||
|
// (重入不再 reset),共享引用可别名,无 `&`/`&mut` 混用。
|
||||||
|
// 重入深度独立存于 `Cell`(`Copy` 类型内部可变),嵌套读写不产生借用冲突。
|
||||||
|
thread_local! {
|
||||||
|
static PARSE_ALLOCATOR: UnsafeCell<Allocator> = UnsafeCell::new(Allocator::new());
|
||||||
|
static PARSE_DEPTH: Cell<usize> = const { Cell::new(0) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 重入深度守卫:出口(含 panic 展开)把深度减一,防深度泄漏。
|
||||||
|
struct DepthGuard<'a>(&'a Cell<usize>);
|
||||||
|
|
||||||
|
impl Drop for DepthGuard<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.0.set(self.0.get() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 在线程本地分配器上执行一次解析上下文:闭包内完成解析与编译,
|
||||||
|
/// AST 生命周期被闭包边界约束。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 闭包不得把 AST 逃逸出闭包边界:下一次顶层入口会 reset 分配器。
|
||||||
|
/// - 闭包内重入本助手(嵌套解析)安全:深度非零时跳过 reset,
|
||||||
|
/// 嵌套解析共享同一分配器,AST 在外层退出前全部有效。
|
||||||
|
///
|
||||||
|
/// # 副作用
|
||||||
|
/// - 深度为零时 reset 分配器(bump 指针归零,高水位 chunk 保留);
|
||||||
|
/// 重入深度入口加一、出口减一(含 panic 展开路径)。
|
||||||
|
pub fn with_parse_allocator<R, F>(f: F) -> R
|
||||||
|
where
|
||||||
|
F: for<'a> FnOnce(&'a Allocator) -> R,
|
||||||
|
{
|
||||||
|
PARSE_DEPTH.with(|depth| {
|
||||||
|
let is_root = depth.get() == 0;
|
||||||
|
depth.set(depth.get() + 1);
|
||||||
|
let _guard = DepthGuard(depth);
|
||||||
|
PARSE_ALLOCATOR.with(|cell| {
|
||||||
|
let ptr = cell.get();
|
||||||
|
// reset 只在最外层执行:此刻尚无共享引用存活,`&mut` 独占安全。
|
||||||
|
if is_root {
|
||||||
|
unsafe { (*ptr).reset() };
|
||||||
|
}
|
||||||
|
// 共享引用跨闭包存活;重入只再产生共享引用,无 `&mut` 混用。
|
||||||
|
let alloc = unsafe { &*ptr };
|
||||||
|
f(alloc)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// 把 `source` 解析为 AST 根节点 `Program`,AST 分配在 `allocator` 中。
|
/// 把 `source` 解析为 AST 根节点 `Program`,AST 分配在 `allocator` 中。
|
||||||
///
|
///
|
||||||
/// 使用 oxc 默认 `SourceType`(严格模式由语法自身决定)。返回 `Ok(program)`
|
/// 使用 oxc 默认 `SourceType`(严格模式由语法自身决定)。返回 `Ok(program)`
|
||||||
|
|||||||
@@ -145,30 +145,35 @@ fn run_test_inner(
|
|||||||
return TestResult::skip(path.to_path_buf(), e);
|
return TestResult::skip(path.to_path_buf(), e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let alloc = oxide_parser::Allocator::default();
|
// 线程本地分配器:解析与编译同闭包内完成,AST 生命周期被闭包边界约束。
|
||||||
let program = match oxide_parser::parse_module(&alloc, &code) {
|
// 闭包返回模块列表或提前判定的结果,外层拆包:Ok 取模块,Err 直接返回结果。
|
||||||
Ok(p) => p,
|
match oxide_parser::with_parse_allocator(|alloc| {
|
||||||
Err(errs) => {
|
// 解析模块:解析失败按 negative 元数据判定 pass/fail,短路返回。
|
||||||
|
let program = oxide_parser::parse_module(alloc, &code).map_err(|errs| {
|
||||||
let dur = start.elapsed().as_millis() as u64;
|
let dur = start.elapsed().as_millis() as u64;
|
||||||
let msg = format!("parse error: {}", errs[0].message);
|
let msg = format!("parse error: {}", errs[0].message);
|
||||||
if meta.negative.is_some() {
|
if meta.negative.is_some() {
|
||||||
return TestResult::pass(path.to_path_buf(), dur, msg);
|
TestResult::pass(path.to_path_buf(), dur, msg)
|
||||||
|
} else {
|
||||||
|
TestResult::fail(path.to_path_buf(), dur, msg)
|
||||||
}
|
}
|
||||||
return TestResult::fail(path.to_path_buf(), dur, msg);
|
})?;
|
||||||
}
|
let mut loader = Test262ModuleLoader;
|
||||||
};
|
match compiler.compile_module(&program, path.to_string_lossy().as_ref(), &mut loader) {
|
||||||
let mut loader = Test262ModuleLoader;
|
Ok(m) => Ok(vec![Arc::new(m)]),
|
||||||
match compiler.compile_module(&program, path.to_string_lossy().as_ref(), &mut loader) {
|
Err(e) => {
|
||||||
Ok(m) => vec![Arc::new(m)],
|
let dur = start.elapsed().as_millis() as u64;
|
||||||
Err(e) => {
|
let msg = format!("compile error: {e}");
|
||||||
let dur = start.elapsed().as_millis() as u64;
|
match classify_compile_error(&msg, meta.negative.is_some(), no_skip) {
|
||||||
let msg = format!("compile error: {e}");
|
TestOutcome::Pass(m) => Err(TestResult::pass(path.to_path_buf(), dur, m)),
|
||||||
match classify_compile_error(&msg, meta.negative.is_some(), no_skip) {
|
TestOutcome::Fail(m) => Err(TestResult::fail(path.to_path_buf(), dur, m)),
|
||||||
TestOutcome::Pass(m) => return TestResult::pass(path.to_path_buf(), dur, m),
|
TestOutcome::Skip(m) => Err(TestResult::skip(path.to_path_buf(), m)),
|
||||||
TestOutcome::Fail(m) => return TestResult::fail(path.to_path_buf(), dur, m),
|
}
|
||||||
TestOutcome::Skip(m) => return TestResult::skip(path.to_path_buf(), m),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}) {
|
||||||
|
Ok(modules) => modules,
|
||||||
|
Err(result) => return result,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// script 臂两模块方案:前缀模块按 includes 组合缓存(免每测试重解析重编译),
|
// script 臂两模块方案:前缀模块按 includes 组合缓存(免每测试重解析重编译),
|
||||||
|
|||||||
Reference in New Issue
Block a user