summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2024-04-14 17:15:17 -0400
committerGitHub <noreply@github.com>2024-04-14 17:15:17 -0400
commite277490c821d20280137ca54eede8502caf62bbd (patch)
treeb2653e570bca449167b968ae8d4f9331553b5f52 /cli
parent76df7d7c9bb7b6b552fd33efbedb28e21969d46c (diff)
perf: do not clone swc `Program` when transpiling (#23365)
Diffstat (limited to 'cli')
-rw-r--r--cli/cache/parsed_source.rs51
-rw-r--r--cli/emit.rs24
2 files changed, 51 insertions, 24 deletions
diff --git a/cli/cache/parsed_source.rs b/cli/cache/parsed_source.rs
index 8d98587e2..94accb616 100644
--- a/cli/cache/parsed_source.rs
+++ b/cli/cache/parsed_source.rs
@@ -8,8 +8,10 @@ use deno_ast::ModuleSpecifier;
use deno_ast::ParsedSource;
use deno_core::parking_lot::Mutex;
use deno_graph::CapturingModuleParser;
+use deno_graph::DefaultModuleParser;
use deno_graph::ModuleParser;
use deno_graph::ParseOptions;
+use deno_graph::ParsedSourceStore;
/// Lazily parses JS/TS sources from a `deno_graph::ModuleGraph` given
/// a `ParsedSourceCache`. Note that deno_graph doesn't necessarily cause
@@ -54,30 +56,38 @@ impl ParsedSourceCache {
&self,
module: &deno_graph::JsModule,
) -> Result<ParsedSource, deno_ast::ParseDiagnostic> {
- self.get_or_parse_module(
- &module.specifier,
- module.source.clone(),
- module.media_type,
- )
+ let parser = self.as_capturing_parser();
+ // this will conditionally parse because it's using a CapturingModuleParser
+ parser.parse_module(ParseOptions {
+ specifier: &module.specifier,
+ source: module.source.clone(),
+ media_type: module.media_type,
+ // don't bother enabling because this method is currently only used for vendoring
+ scope_analysis: false,
+ })
}
- /// Gets the matching `ParsedSource` from the cache
- /// or parses a new one and stores that in the cache.
- pub fn get_or_parse_module(
+ pub fn remove_or_parse_module(
&self,
- specifier: &deno_graph::ModuleSpecifier,
+ specifier: &ModuleSpecifier,
source: Arc<str>,
media_type: MediaType,
- ) -> deno_core::anyhow::Result<ParsedSource, deno_ast::ParseDiagnostic> {
- let parser = self.as_capturing_parser();
- // this will conditionally parse because it's using a CapturingModuleParser
- parser.parse_module(ParseOptions {
+ ) -> Result<ParsedSource, deno_ast::ParseDiagnostic> {
+ if let Some(parsed_source) = self.remove_parsed_source(specifier) {
+ if parsed_source.media_type() == media_type
+ && parsed_source.text_info().text_str() == source.as_ref()
+ {
+ return Ok(parsed_source);
+ }
+ }
+ let options = ParseOptions {
specifier,
source,
media_type,
// don't bother enabling because this method is currently only used for emitting
scope_analysis: false,
- })
+ };
+ DefaultModuleParser.parse_module(options)
}
/// Frees the parsed source from memory.
@@ -100,7 +110,7 @@ impl ParsedSourceCache {
impl deno_graph::ParsedSourceStore for ParsedSourceCache {
fn set_parsed_source(
&self,
- specifier: deno_graph::ModuleSpecifier,
+ specifier: ModuleSpecifier,
parsed_source: ParsedSource,
) -> Option<ParsedSource> {
self.sources.lock().insert(specifier, parsed_source)
@@ -108,14 +118,21 @@ impl deno_graph::ParsedSourceStore for ParsedSourceCache {
fn get_parsed_source(
&self,
- specifier: &deno_graph::ModuleSpecifier,
+ specifier: &ModuleSpecifier,
) -> Option<ParsedSource> {
self.sources.lock().get(specifier).cloned()
}
+ fn remove_parsed_source(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> Option<ParsedSource> {
+ self.sources.lock().remove(specifier)
+ }
+
fn get_scope_analysis_parsed_source(
&self,
- specifier: &deno_graph::ModuleSpecifier,
+ specifier: &ModuleSpecifier,
) -> Option<ParsedSource> {
let mut sources = self.sources.lock();
let parsed_source = sources.get(specifier)?;
diff --git a/cli/emit.rs b/cli/emit.rs
index 0c79b11ee..07343f39d 100644
--- a/cli/emit.rs
+++ b/cli/emit.rs
@@ -93,14 +93,24 @@ impl Emitter {
{
Ok(emit_code.into())
} else {
- // this will use a cached version if it exists
- let parsed_source = self.parsed_source_cache.get_or_parse_module(
+ // nothing else needs the parsed source at this point, so remove from
+ // the cache in order to not transpile owned
+ let parsed_source = self.parsed_source_cache.remove_or_parse_module(
specifier,
source.clone(),
media_type,
)?;
- let transpiled_source =
- parsed_source.transpile(&self.transpile_options, &self.emit_options)?;
+ let transpiled_source = match parsed_source
+ .transpile_owned(&self.transpile_options, &self.emit_options)
+ {
+ Ok(result) => result?,
+ Err(parsed_source) => {
+ // transpile_owned is more efficient and should be preferred
+ debug_assert!(false, "Transpile owned failed.");
+ parsed_source
+ .transpile(&self.transpile_options, &self.emit_options)?
+ }
+ };
debug_assert!(transpiled_source.source_map.is_none());
self.emit_cache.set_emit_code(
specifier,
@@ -124,11 +134,11 @@ impl Emitter {
let source_arc: Arc<str> = source_code.into();
let parsed_source = self
.parsed_source_cache
- .get_or_parse_module(specifier, source_arc, media_type)?;
+ .remove_or_parse_module(specifier, source_arc, media_type)?;
let mut options = self.emit_options;
options.source_map = SourceMapOption::None;
- let transpiled_source =
- parsed_source.transpile(&self.transpile_options, &options)?;
+ let transpiled_source = parsed_source
+ .transpile_owned_with_fallback(&self.transpile_options, &options)?;
Ok(transpiled_source.text)
}