10000 Fuse emitting and printing of trees in the backend · scala-js/scala-js@22db2f6 · GitHub
[go: up one dir, main page]

Skip to content

Commit 22db2f6

Browse files
committed
Fuse emitting and printing of trees in the backend
This allows us to use the Emitter's powerful caching mechanism to directly cache printed trees (as byte buffers) and not cache JavaScript trees anymore at all. This reduces in-between run memory usage on the test suite from 1.12 GB (not GiB) to 1.00 GB on my machine (roughly 10%). Runtime performance (both batch and incremental) is unaffected. It is worth pointing out, that due to how the Emitter caches trees, classes that end up being ES6 classes is performed will be held twice in memory (once the individual methods, once the entire class). On the test suite, this is the case for 710 cases out of 6538.
1 parent 8daa2a4 commit 22db2f6

File tree

10 files changed

+394
-262
lines changed

10 files changed

+394
-262
lines changed

linker/jvm/src/main/scala/org/scalajs/linker/backend/closure/ClosureAstTransformer.scala

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import org.scalajs.ir
1818
import ir.Position
1919
import ir.Position.NoPosition
2020

21+
import org.scalajs.linker.backend.emitter.Emitter
2122
import org.scalajs.linker.backend.javascript.Trees._
2223
import org.scalajs.linker.backend.javascript.SourceFileUtil
2324

@@ -30,24 +31,34 @@ import java.lang.{Double => JDouble}
3031
import java.net.URI
3132

3233
private[closure] object ClosureAstTransformer {
33-
def transformScript(topLevelTrees: List[Tree], featureSet: FeatureSet,
34-
relativizeBaseURI: Option[URI]): Node = {
35-
val transformer = new ClosureAstTransformer(featureSet, relativizeBaseURI)
36-
transformer.transformScript(topLevelTrees)
37-
}
34+
final class Chunk private[ClosureAstTransformer] (
35+
private[ClosureAstTransformer] val nodes: List[Node]
36+
) extends Transformed.Value
3837
}
3938

40-
private class ClosureAstTransformer(featureSet: FeatureSet,
41-
relativizeBaseURI: Option[URI]) {
39+
private[closure] class ClosureAstTransformer(featureSet: FeatureSet,
40+
relativizeBaseURI: Option[URI]) extends Emitter.PostTransformer[ClosureAstTransformer.Chunk] {
41+
import ClosureAstTransformer.Chunk
42+
4243
private val dummySourceName = new java.net.URI("virtualfile:scala.js-ir")
4344

44-
def transformScript(topLevelTrees: List[Tree]): Node = {
45+
def transformScript(chunks: List[Chunk]): Node = {
4546
val script = setNodePosition(new Node(Token.SCRIPT), NoPosition)
46-
transformBlockStats(topLevelTrees)(NoPosition).foreach(script.addChildToBack(_))
47+
48+
for {
49+
chunk <- chunks
50+
node <- chunk.nodes
51+
} {
52+
script.addChildToBack(node)
53+
}
54+
4755
script.putProp(Node.FEATURE_SET, featureSet)
4856
script
4957
}
5058

59+
def transformStats(trees: List[Tree], indent: Int): Chunk =
60+
new Chunk(transformBlockStats(trees)(NoPosition))
61+
5162
private def transformStat(tree: Tree)(implicit parentPos: Position): Node =
5263
innerTransformStat(tree, tree.pos orElse parentPos)
5364

@@ -460,6 +471,10 @@ private class ClosureAstTransformer(featureSet: FeatureSet,
460471
case DocComment(text) :: tss =>
461472
loop(tss, nextIsCtor = text.startsWith("@constructor"), acc)
462473

474+
case Transformed(chunk: Chunk) :: tss =>
475+
assert(!nextIsCtor)
476+
loop(tss, nextIsCtor = false, chunk.nodes reverse_::: acc)
477+
463478
case t :: tss =>
464479
val node = transformStat(t)
465480
if (nextIsCtor) {

linker/jvm/src/main/scala/org/scalajs/linker/backend/closure/ClosureLinkerBackend.scala

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,6 @@ final class ClosureLinkerBackend(config: LinkerBackendImpl.Config)
5353
require(moduleKind != ModuleKind.ESModule,
5454
s"Cannot use module kind $moduleKind with the Closure Compiler")
5555

56-
private[this] val emitter = {
57-
val emitterConfig = Emitter.Config(config.commonConfig.coreSpec)
58-
.withJSHeader(config.jsHeader)
59-
.withOptimizeBracketSelects(false)
60-
.withTrackAllGlobalRefs(true)
61-
.withInternalModulePattern(m => OutputPatternsImpl.moduleName(config.outputPatterns, m.id))
62-
63-
new Emitter(emitterConfig)
64-
}
65-
66-
val symbolRequirements: SymbolRequirement = emitter.symbolRequirements
67-
68-
override def injectedIRFiles: Seq[IRFile] = emitter.injectedIRFiles
69-
7056
private val languageMode: ClosureOptions.LanguageMode = {
7157
import ClosureOptions.LanguageMode._
7258

@@ -85,6 +71,23 @@ final class ClosureLinkerBackend(config: LinkerBackendImpl.Config)
8571
}
8672
}
8773

74+
private[this] val transformer = new ClosureAstTransformer(
75+
languageMode.toFeatureSet(), config.relativizeSourceMapBase)
76+
77+
private[this] val emitter: Emitter[ClosureAstTransformer.Chunk] = {
78+
val emitterConfig = Emitter.Config(config.commonConfig.coreSpec)
79+
.withJSHeader(config.jsHeader)
80+
.withOptimizeBracketSelects(false)
81+
.withTrackAllGlobalRefs(true)
82+
.withInternalModulePattern(m => OutputPatternsImpl.moduleName(config.outputPatterns, m.id))
83+
84+
new Emitter(emitterConfig, transformer)
85+
}
86+
87+
val symbolRequirements: SymbolRequirement = emitter.symbolRequirements
88+
89+
override def injectedIRFiles: Seq[IRFile] = emitter.injectedIRFiles
90+
8891
/** Emit the given [[standard.ModuleSet ModuleSet]] to the target output.
8992
*
9093
* @param moduleSet [[standard.ModuleSet ModuleSet]] to emit
@@ -129,9 +132,8 @@ final class ClosureLinkerBackend(config: LinkerBackendImpl.Config)
129132
}
130133
}
131134

132-
private def buildChunk(topLevelTrees: List[js.Tree]): JSChunk = {
133-
val root = ClosureAstTransformer.transformScript(topLevelTrees,
134-
languageMode.toFeatureSet(), config.relativizeSourceMapBase)
135+
private def buildChunk(topLevelTrees: List[ClosureAstTransformer.Chunk]): JSChunk = {
136+
val root = transformer.transformScript(topLevelTrees)
135137

136138
val chunk = new JSChunk("Scala.js")
137139
chunk.add(new CompilerInput(new SyntheticAst(root)))

0 commit comments

Comments
 (0)
0