@@ -2,9 +2,11 @@ package bloop.scalajs
22
33import java .nio .file .Path
44
5+ import scala .collection .concurrent .TrieMap
56import scala .concurrent .Await
67import scala .concurrent .ExecutionContext
78import scala .concurrent .duration .Duration
9+ import scala .ref .SoftReference
810
911import bloop .config .Config .JsConfig
1012import bloop .config .Config .LinkerMode
@@ -51,6 +53,40 @@ object JsBridge {
5153 }
5254 override def trace (t : => Throwable ): Unit = logger.trace(t)
5355 }
56+ private object ScalaJSLinker {
57+ private val cache = TrieMap .empty[Path , SoftReference [(JsConfig , Linker )]]
58+ def reuseOrCreate (config : JsConfig , target : Path ): Linker =
59+ if (config.mode == LinkerMode .Release ) createLinker(config)
60+ else
61+ cache.get(target) match {
62+ case Some (SoftReference ((`config`, linker))) => linker
63+ case _ =>
64+ val newLinker = createLinker(config)
65+ cache.update(target, SoftReference ((config, newLinker)))
66+ newLinker
67+ }
68+ private def createLinker (config : JsConfig ): Linker = {
69+ val isFullLinkJS = config.mode == LinkerMode .Release
70+ val semantics =
71+ if (isFullLinkJS) Semantics .Defaults .optimized
72+ else Semantics .Defaults
73+ val scalaJSModuleKind = config.kind match {
74+ case ModuleKindJS .NoModule => ScalaJSModuleKind .NoModule
75+ case ModuleKindJS .CommonJSModule => ScalaJSModuleKind .CommonJSModule
76+ case ModuleKindJS .ESModule => ScalaJSModuleKind .ESModule
77+ }
78+
79+ val useClosure = isFullLinkJS && config.kind != ModuleKindJS .ESModule
80+
81+ val linkerConfig = StandardConfig ()
82+ .withClosureCompiler(useClosure)
83+ .withSemantics(semantics)
84+ .withModuleKind(scalaJSModuleKind)
85+ .withSourceMap(config.emitSourceMaps)
86+
87+ StandardImpl .clearableLinker(linkerConfig)
88+ }
89+ }
5490
5591 def link (
5692 config : JsConfig ,
@@ -64,17 +100,7 @@ object JsBridge {
64100 ): Unit = {
65101 implicit val ec = executionContext
66102 implicit val logFilter : DebugFilter = DebugFilter .Link
67- val enableOptimizer = config.mode == LinkerMode .Release
68- val semantics = config.mode match {
69- case LinkerMode .Debug => Semantics .Defaults
70- case LinkerMode .Release => Semantics .Defaults .optimized
71- }
72-
73- val moduleKind = config.kind match {
74- case ModuleKindJS .NoModule => ScalaJSModuleKind .NoModule
75- case ModuleKindJS .CommonJSModule => ScalaJSModuleKind .CommonJSModule
76- case ModuleKindJS .ESModule => ScalaJSModuleKind .ESModule
77- }
103+ val linker = ScalaJSLinker .reuseOrCreate(config, target)
78104
79105 val cache = StandardImpl .irFileCache().newCache
80106 val irContainersPairs = PathIRContainer .fromClasspath(classpath)
@@ -101,18 +127,10 @@ object JsBridge {
101127 }
102128
103129 val output = LinkerOutput (PathOutputFile (target))
104- val jsConfig = StandardConfig ()
105- .withOptimizer(enableOptimizer)
106- .withClosureCompilerIfAvailable(enableOptimizer)
107- .withSemantics(semantics)
108- .withModuleKind(moduleKind)
109- .withSourceMap(config.emitSourceMaps)
110130
111131 val resultFuture = for {
112132 libraryIRs <- libraryIrsFuture
113- _ <- StandardImpl
114- .linker(jsConfig)
115- .link(libraryIRs, moduleInitializers, output, new Logger (logger))
133+ _ <- linker.link(libraryIRs, moduleInitializers, output, new Logger (logger))
116134 } yield ()
117135
118136 Await .result(resultFuture, Duration .Inf )
0 commit comments