mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 18:43:44 +00:00
perf(codegen)!: borrow sourcemaps from codegen (#23422)
Summary: - Upgrade oxc_sourcemap to 8.0.1. - Return borrowed SourceMap from CodegenReturn. - Support no-sourcemap feature builds used by benchmarks. AI-assisted: yes
This commit is contained in:
1 parent
d241add8d8
commit
7a24911846
10 files changed
+77
-39
No files matched your search
Generated
+2
-2
@@ -2628,9 +2628,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_sourcemap"
|
||||
version = "7.0.0"
|
||||
version = "8.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3866f9075027840e0711b52e15d2e1ba076fc5f5f01c96eeedd26375410641"
|
||||
checksum = "174d2498c2390ccfab0a9caaf47ef5accda1d509aaa34a5be8f45e00e5299f04"
|
||||
dependencies = [
|
||||
"base64-simd",
|
||||
"json-escape-simd",
|
||||
|
||||
+1
-1
@@ -175,7 +175,7 @@ json-strip-comments = "3.1.0" # Strip JSON comments
|
||||
oxc-browserslist = "3.0.0" # Browser compatibility queries
|
||||
oxc_index = { version = "5.0.0", features = ["nonmax", "serde"] } # Type-safe indices
|
||||
oxc_resolver = "11.16.3" # Module resolution
|
||||
oxc_sourcemap = "7.0.0" # Source map generation
|
||||
oxc_sourcemap = "8.0.1" # Source map generation
|
||||
|
||||
#
|
||||
allocator-api2 = "=0.2.21" # Allocator trait
|
||||
|
||||
@@ -27,7 +27,7 @@ impl CompilerInterface for Compiler {
|
||||
self.errors.extend(errors);
|
||||
}
|
||||
|
||||
fn after_codegen(&mut self, ret: CodegenReturn) {
|
||||
fn after_codegen(&mut self, ret: CodegenReturn<'_>) {
|
||||
self.printed = ret.code;
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ pub trait CompilerInterface {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn after_isolated_declarations(&mut self, _ret: CodegenReturn) {}
|
||||
fn after_isolated_declarations(&mut self, _ret: CodegenReturn<'_>) {}
|
||||
|
||||
fn after_transform(
|
||||
&mut self,
|
||||
@@ -122,7 +122,7 @@ pub trait CompilerInterface {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn after_codegen(&mut self, _ret: CodegenReturn) {}
|
||||
fn after_codegen(&mut self, _ret: CodegenReturn<'_>) {}
|
||||
|
||||
fn compile(&mut self, source_text: &str, source_type: SourceType, source_path: &Path) {
|
||||
let allocator = Allocator::default();
|
||||
@@ -308,13 +308,13 @@ pub trait CompilerInterface {
|
||||
Mangler::new().with_options(options).build(program)
|
||||
}
|
||||
|
||||
fn codegen(
|
||||
fn codegen<'a>(
|
||||
&self,
|
||||
program: &Program<'_>,
|
||||
program: &Program<'a>,
|
||||
source_path: &Path,
|
||||
mangler_return: Option<ManglerReturn>,
|
||||
options: CodegenOptions,
|
||||
) -> CodegenReturn {
|
||||
) -> CodegenReturn<'a> {
|
||||
let mut options = options;
|
||||
if self.enable_sourcemap() {
|
||||
options.source_map_path = Some(source_path.to_path_buf());
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
//! Code adapted from
|
||||
//! * [esbuild](https://github.com/evanw/esbuild/blob/v0.24.0/internal/js_printer/js_printer.go)
|
||||
|
||||
#[cfg(not(feature = "sourcemap"))]
|
||||
use std::marker::PhantomData;
|
||||
use std::{borrow::Cow, cmp, slice};
|
||||
|
||||
use cow_utils::CowUtils;
|
||||
@@ -48,7 +50,7 @@ pub use oxc_data_structures::code_buffer::IndentChar;
|
||||
|
||||
/// Output from [`Codegen::build`]
|
||||
#[non_exhaustive]
|
||||
pub struct CodegenReturn {
|
||||
pub struct CodegenReturn<'a> {
|
||||
/// The generated source code.
|
||||
pub code: String,
|
||||
|
||||
@@ -56,7 +58,10 @@ pub struct CodegenReturn {
|
||||
///
|
||||
/// You must set [`CodegenOptions::source_map_path`] for this to be [`Some`].
|
||||
#[cfg(feature = "sourcemap")]
|
||||
pub map: Option<oxc_sourcemap::OwnedSourceMap>,
|
||||
pub map: Option<oxc_sourcemap::SourceMap<'a>>,
|
||||
|
||||
#[cfg(not(feature = "sourcemap"))]
|
||||
_source_map_lifetime: PhantomData<&'a ()>,
|
||||
|
||||
/// All the legal comments returned from [LegalComment::Linked] or [LegalComment::External].
|
||||
pub legal_comments: Vec<Comment>,
|
||||
@@ -246,7 +251,7 @@ impl<'a> Codegen<'a> {
|
||||
///
|
||||
/// A source map will be generated if [`CodegenOptions::source_map_path`] is set.
|
||||
#[must_use]
|
||||
pub fn build(mut self, program: &Program<'a>) -> CodegenReturn {
|
||||
pub fn build(mut self, program: &Program<'a>) -> CodegenReturn<'a> {
|
||||
self.quote = if self.options.single_quote { Quote::Single } else { Quote::Double };
|
||||
self.source_text = Some(program.source_text);
|
||||
self.indent = self.options.initial_indent;
|
||||
@@ -265,6 +270,8 @@ impl<'a> Codegen<'a> {
|
||||
code,
|
||||
#[cfg(feature = "sourcemap")]
|
||||
map,
|
||||
#[cfg(not(feature = "sourcemap"))]
|
||||
_source_map_lifetime: PhantomData,
|
||||
legal_comments,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::path::Path;
|
||||
use std::{borrow::Cow, path::Path};
|
||||
|
||||
use oxc_index::{IndexVec, define_nonmax_u32_index_type};
|
||||
use oxc_span::Span;
|
||||
use oxc_syntax::line_terminator::{LS, LS_LAST_2_BYTES, LS_OR_PS_FIRST_BYTE, PS, PS_LAST_2_BYTES};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
/// Number of lines to check with linear search when translating byte position to line index
|
||||
const LINE_SEARCH_LINEAR_ITERATIONS: usize = 16;
|
||||
@@ -45,14 +46,15 @@ pub struct ColumnOffsets {
|
||||
columns: Box<[u32]>,
|
||||
}
|
||||
|
||||
#[expect(clippy::struct_field_names)]
|
||||
pub struct SourcemapBuilder<'a> {
|
||||
source_id: u32,
|
||||
source_name: String,
|
||||
original_source: &'a str,
|
||||
names: Vec<&'a str>,
|
||||
names_map: FxHashMap<&'a str, u32>,
|
||||
tokens: Vec<oxc_sourcemap::Token>,
|
||||
last_generated_update: usize,
|
||||
last_position: Option<u32>,
|
||||
line_offset_tables: LineOffsetTables,
|
||||
sourcemap_builder: oxc_sourcemap::SourceMapBuilder,
|
||||
generated_line: u32,
|
||||
generated_column: u32,
|
||||
/// Tracks the last accessed line index to optimize sequential lookups in `search_original_line_and_column`.
|
||||
@@ -63,25 +65,37 @@ pub struct SourcemapBuilder<'a> {
|
||||
|
||||
impl<'a> SourcemapBuilder<'a> {
|
||||
pub fn new(path: &Path, source_text: &'a str) -> Self {
|
||||
let mut sourcemap_builder = oxc_sourcemap::SourceMapBuilder::default();
|
||||
let line_offset_tables = Self::generate_line_offset_tables(source_text);
|
||||
let source_id =
|
||||
sourcemap_builder.set_source_and_content(path.to_string_lossy().as_ref(), source_text);
|
||||
Self {
|
||||
source_id,
|
||||
source_name: path.to_string_lossy().into_owned(),
|
||||
original_source: source_text,
|
||||
names: Vec::new(),
|
||||
names_map: FxHashMap::default(),
|
||||
tokens: Vec::new(),
|
||||
last_generated_update: 0,
|
||||
last_position: None,
|
||||
line_offset_tables,
|
||||
sourcemap_builder,
|
||||
generated_line: 0,
|
||||
generated_column: 0,
|
||||
last_line_lookup: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_sourcemap(self) -> oxc_sourcemap::OwnedSourceMap {
|
||||
self.sourcemap_builder.into_owned_sourcemap()
|
||||
pub fn into_sourcemap(mut self) -> oxc_sourcemap::SourceMap<'a> {
|
||||
self.names.shrink_to_fit();
|
||||
self.tokens.shrink_to_fit();
|
||||
|
||||
oxc_sourcemap::SourceMap::from_parts(oxc_sourcemap::SourceMapParts {
|
||||
file: None,
|
||||
names: self.names.into_iter().map(Cow::Borrowed).collect(),
|
||||
source_root: None,
|
||||
sources: vec![Cow::Owned(self.source_name)],
|
||||
source_contents: vec![Some(Cow::Borrowed(self.original_source))],
|
||||
tokens: self.tokens.into_boxed_slice(),
|
||||
token_chunks: None,
|
||||
x_google_ignore_list: None,
|
||||
debug_id: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_source_mapping_for_name(&mut self, output: &[u8], span: Span, name: &str) {
|
||||
@@ -99,24 +113,34 @@ impl<'a> SourcemapBuilder<'a> {
|
||||
self.add_source_mapping(output, span.start, token_name);
|
||||
}
|
||||
|
||||
pub fn add_source_mapping(&mut self, output: &[u8], position: u32, name: Option<&str>) {
|
||||
pub fn add_source_mapping(&mut self, output: &[u8], position: u32, name: Option<&'a str>) {
|
||||
if self.last_position == Some(position) {
|
||||
return;
|
||||
}
|
||||
let (original_line, original_column) = self.search_original_line_and_column(position);
|
||||
self.update_generated_line_and_column(output);
|
||||
let name_id = name.map(|s| self.sourcemap_builder.add_name(s));
|
||||
self.sourcemap_builder.add_token(
|
||||
let name_id = name.map(|s| self.add_name(s));
|
||||
self.tokens.push(oxc_sourcemap::Token::new(
|
||||
self.generated_line,
|
||||
self.generated_column,
|
||||
original_line,
|
||||
original_column,
|
||||
Some(self.source_id),
|
||||
Some(0),
|
||||
name_id,
|
||||
);
|
||||
));
|
||||
self.last_position = Some(position);
|
||||
}
|
||||
|
||||
fn add_name(&mut self, name: &'a str) -> u32 {
|
||||
if let Some(&id) = self.names_map.get(name) {
|
||||
return id;
|
||||
}
|
||||
let id = u32::try_from(self.names.len()).expect("sourcemap names length should fit in u32");
|
||||
self.names_map.insert(name, id);
|
||||
self.names.push(name);
|
||||
id
|
||||
}
|
||||
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
fn search_original_line_and_column(&mut self, position: u32) -> (u32, u32) {
|
||||
let original_line = self.search_original_line(position);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions, CodegenReturn};
|
||||
use oxc_ast::ast::Comment;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_parser::{ParseOptions, Parser};
|
||||
use oxc_span::SourceType;
|
||||
|
||||
@@ -95,14 +96,20 @@ pub fn codegen(source_text: &str) -> String {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn codegen_options(source_text: &str, options: &CodegenOptions) -> CodegenReturn {
|
||||
pub fn codegen_options(source_text: &str, options: &CodegenOptions) -> CodegenTestReturn {
|
||||
let allocator = Allocator::default();
|
||||
let source_type = SourceType::ts();
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
assert!(ret.diagnostics.is_empty(), "Parse errors: {:?}", ret.diagnostics);
|
||||
let mut options = options.clone();
|
||||
options.single_quote = true;
|
||||
Codegen::new().with_options(options).build(&ret.program)
|
||||
let ret = Codegen::new().with_options(options).build(&ret.program);
|
||||
CodegenTestReturn { code: ret.code, legal_comments: ret.legal_comments }
|
||||
}
|
||||
|
||||
pub struct CodegenTestReturn {
|
||||
pub code: String,
|
||||
pub legal_comments: Vec<Comment>,
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
||||
@@ -81,15 +81,15 @@ fn main() -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn minify(
|
||||
allocator: &Allocator,
|
||||
source_text: &str,
|
||||
fn minify<'a>(
|
||||
allocator: &'a Allocator,
|
||||
source_text: &'a str,
|
||||
source_type: SourceType,
|
||||
source_map_path: Option<PathBuf>,
|
||||
mangle: bool,
|
||||
nospace: bool,
|
||||
max_iterations: Option<u8>,
|
||||
) -> CodegenReturn {
|
||||
) -> CodegenReturn<'a> {
|
||||
let ret = Parser::new(allocator, source_text, source_type).parse();
|
||||
assert!(ret.diagnostics.is_empty());
|
||||
let mut program = ret.program;
|
||||
|
||||
@@ -871,12 +871,12 @@ impl CompilerInterface for Compiler {
|
||||
self.inject.clone()
|
||||
}
|
||||
|
||||
fn after_codegen(&mut self, ret: CodegenReturn) {
|
||||
fn after_codegen(&mut self, ret: CodegenReturn<'_>) {
|
||||
self.printed = ret.code;
|
||||
self.printed_sourcemap = ret.map.map(SourceMap::from);
|
||||
}
|
||||
|
||||
fn after_isolated_declarations(&mut self, ret: CodegenReturn) {
|
||||
fn after_isolated_declarations(&mut self, ret: CodegenReturn<'_>) {
|
||||
self.declaration.replace(ret.code);
|
||||
self.declaration_map = ret.map.map(SourceMap::from);
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ impl CompilerInterface for Driver {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn after_codegen(&mut self, ret: CodegenReturn) {
|
||||
fn after_codegen(&mut self, ret: CodegenReturn<'_>) {
|
||||
self.printed = ret.code;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ impl CompilerInterface for Driver {
|
||||
self.errors.extend(errors);
|
||||
}
|
||||
|
||||
fn after_codegen(&mut self, ret: CodegenReturn) {
|
||||
fn after_codegen(&mut self, ret: CodegenReturn<'_>) {
|
||||
self.printed = ret.code;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user