Skip to content

Commit

Permalink
try to avoid cloning AST during code generation, pass final_read_hint
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Feb 13, 2025
1 parent 2deb462 commit cf5d4f6
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 24 deletions.
73 changes: 60 additions & 13 deletions turbopack/crates/turbopack-ecmascript/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,24 @@ pub mod utils;
pub mod webpack;
pub mod worker_chunk;

use std::fmt::{Display, Formatter};
use std::{
fmt::{Display, Formatter},
mem::take,
sync::Arc,
};

use anyhow::Result;
use chunk::EcmascriptChunkItem;
use code_gen::{CodeGenerateable, CodeGeneration, CodeGenerationHoistedStmt};
use either::Either;
use parse::{parse, ParseResult};
use path_visitor::ApplyVisitors;
use references::esm::UrlRewriteBehavior;
pub use references::{AnalyzeEcmascriptModuleResult, TURBOPACK_HELPER};
use serde::{Deserialize, Serialize};
pub use static_code::StaticEcmascriptCode;
use swc_core::{
common::{Globals, Mark, GLOBALS},
common::{comments::Comments, util::take::Take, Globals, Mark, GLOBALS},
ecma::{
ast::{self, ModuleItem, Program, Script},
codegen::{text_writer::JsWriter, Emitter},
Expand Down Expand Up @@ -835,18 +840,51 @@ async fn gen_content_with_code_gens(
generate_source_map: Vc<bool>,
original_source_map: ResolvedVc<OptionStringifiedSourceMap>,
) -> Result<Vc<EcmascriptModuleContent>> {
let parsed = parsed.await?;
let parsed = parsed.final_read_hint().await?;

match &*parsed {
ParseResult::Ok {
program,
source_map,
globals,
eval_context,
comments,
..
} => {
let mut program = program.clone();
ParseResult::Ok { .. } => {
// We need a mutable version of the AST. We try to avoid cloning it by unwrapping the
// ReadRef.
let mut parsed = ReadRef::try_unwrap(parsed);
let (mut program, source_map, globals, eval_context, comments) = match &mut parsed {
Ok(ParseResult::Ok {
program,
source_map,
globals,
eval_context,
comments,
}) => (
program.take(),
&*source_map,
&*globals,
&*eval_context,
match Arc::try_unwrap(take(comments)) {
Ok(comments) => Either::Left(comments),
Err(comments) => Either::Right(comments),
},
),
Err(parsed) => {
let ParseResult::Ok {
program,
source_map,
globals,
eval_context,
comments,
} = &**parsed
else {
unreachable!();
};
(
program.clone(),
source_map,
globals,
eval_context,
Either::Right(comments.clone()),
)
}
_ => unreachable!(),
};

process_content_with_code_gens(
&mut program,
Expand All @@ -864,7 +902,15 @@ async fn gen_content_with_code_gens(
let generate_source_map = *generate_source_map.await?;

{
let comments = comments.consumable();
let comments = match comments {
Either::Left(comments) => Either::Left(comments.into_consumable()),
Either::Right(ref comments) => Either::Right(comments.consumable()),
};
let comments: &dyn Comments = match &comments {
Either::Left(comments) => comments,
Either::Right(comments) => comments,
};

let mut emitter = Emitter {
cfg: swc_core::ecma::codegen::Config::default(),
cm: source_map.clone(),
Expand All @@ -876,6 +922,7 @@ async fn gen_content_with_code_gens(
generate_source_map.then_some(&mut mappings),
),
};

emitter.emit_program(&program)?;
}

Expand Down
49 changes: 38 additions & 11 deletions turbopack/crates/turbopack-ecmascript/src/swc_comments.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{cell::RefCell, mem::take};
use std::{borrow::Cow, cell::RefCell, mem::take};

use rustc_hash::FxHashMap;
use swc_core::{
Expand All @@ -12,6 +12,7 @@ use swc_core::{
/// Immutable version of [SwcComments] which doesn't allow mutation. The `take`
/// variants are still implemented, but do not mutate the content. They are used
/// by the SWC Emitter.
#[derive(Default)]
pub struct ImmutableComments {
pub leading: FxHashMap<BytePos, Vec<Comment>>,
pub trailing: FxHashMap<BytePos, Vec<Comment>>,
Expand Down Expand Up @@ -39,8 +40,12 @@ impl ImmutableComments {
}
}

pub fn into_consumable(self) -> CowComments<'static> {
CowComments::owned(self)
}

pub fn consumable(&self) -> CowComments<'_> {
CowComments::new(self)
CowComments::borrowed(self)
}
}

Expand Down Expand Up @@ -186,25 +191,44 @@ impl Comments for ImmutableComments {
}

pub struct CowComments<'a> {
leading: RefCell<FxHashMap<BytePos, &'a Vec<Comment>>>,
trailing: RefCell<FxHashMap<BytePos, &'a Vec<Comment>>>,
leading: RefCell<FxHashMap<BytePos, Cow<'a, Vec<Comment>>>>,
trailing: RefCell<FxHashMap<BytePos, Cow<'a, Vec<Comment>>>>,
}

impl<'a> CowComments<'a> {
fn new(comments: &'a ImmutableComments) -> Self {
fn borrowed(comments: &'a ImmutableComments) -> Self {
Self {
leading: RefCell::new(
comments
.leading
.iter()
.map(|(&key, value)| (key, value))
.map(|(&key, value)| (key, Cow::Borrowed(value)))
.collect(),
),
trailing: RefCell::new(
comments
.trailing
.iter()
.map(|(&key, value)| (key, value))
.map(|(&key, value)| (key, Cow::Borrowed(value)))
.collect(),
),
}
}

fn owned(comments: ImmutableComments) -> Self {
Self {
leading: RefCell::new(
comments
.leading
.into_iter()
.map(|(key, value)| (key, Cow::Owned(value)))
.collect(),
),
trailing: RefCell::new(
comments
.trailing
.into_iter()
.map(|(key, value)| (key, Cow::Owned(value)))
.collect(),
),
}
Expand Down Expand Up @@ -240,14 +264,17 @@ impl Comments for CowComments<'_> {
&self,
pos: swc_core::common::BytePos,
) -> Option<Vec<swc_core::common::comments::Comment>> {
self.leading.borrow_mut().remove(&pos).map(|v| v.to_owned())
self.leading
.borrow_mut()
.remove(&pos)
.map(|v| v.into_owned())
}

fn get_leading(
&self,
pos: swc_core::common::BytePos,
) -> Option<Vec<swc_core::common::comments::Comment>> {
self.leading.borrow().get(&pos).map(|&v| v.to_owned())
self.leading.borrow().get(&pos).map(|v| (**v).clone())
}

fn add_trailing(
Expand Down Expand Up @@ -281,14 +308,14 @@ impl Comments for CowComments<'_> {
self.trailing
.borrow_mut()
.remove(&pos)
.map(|v| v.to_owned())
.map(|v| v.into_owned())
}

fn get_trailing(
&self,
pos: swc_core::common::BytePos,
) -> Option<Vec<swc_core::common::comments::Comment>> {
self.trailing.borrow().get(&pos).map(|&v| v.to_owned())
self.trailing.borrow().get(&pos).map(|v| (**v).clone())
}

fn add_pure_comment(&self, _pos: swc_core::common::BytePos) {
Expand Down

0 comments on commit cf5d4f6

Please sign in to comment.