Skip to content

Fix #541: Make incremental optimizer honor clean #601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 5, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,12 @@ object ScalaJSPlugin extends Plugin with impl.DependencyBuilders {
// add all the webjars your jsDependencies depend upon
libraryDependencies ++= jsDependencies.value.collect {
case JarJSModuleID(module, _) => module
}
},
// have clean reset incremental optimizer state
clean <<= clean.dependsOn(Def.task {
scalaJSOptimizer.in(Compile, fastOptJS).value.clean()
scalaJSOptimizer.in(Test, fastOptJS).value.clean()
})
)

val scalaJSProjectBaseSettings = Seq(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import ScalaJSPackedClasspath.packOrderLine
class ScalaJSOptimizer {
import ScalaJSOptimizer._

private[this] var logger: Logger = _
private[this] var persistentState: PersistentState = new PersistentState

/** Applies Scala.js-specific optimizations to a Scala.js classpath.
* See [[ScalaJSOptimizer.Inputs]] for details about the required and
Expand All @@ -45,66 +45,34 @@ class ScalaJSOptimizer {
*/
def optimize(inputs: Inputs, outputConfig: OutputConfig,
logger: Logger): Unit = {
this.logger = logger
PersistentState.startRun()
persistentState.startRun()
try {
import inputs._
val analyzer = readClasspathAndCreateAnalyzer(classpath)
val analyzer = readClasspathAndCreateAnalyzer(classpath, logger)
analyzer.computeReachability(manuallyReachable, noWarnMissing)
writeDCEedOutput(inputs, outputConfig, analyzer)
} finally {
PersistentState.endRun()
this.logger = null
persistentState.endRun()
logger.debug(
s"Inc. opt stats: reused: ${persistentState.statsReused} -- "+
s"invalidated: ${persistentState.statsInvalidated} -- "+
s"trees read: ${persistentState.statsTreesRead}")
}
}

/** Resets all persistent state of this optimizer */
def clean(): Unit = {
persistentState = new PersistentState
}

private def readClasspathAndCreateAnalyzer(
classpath: ScalaJSClasspath): Analyzer = {
classpath: ScalaJSClasspath, logger: Logger): Analyzer = {
val userInfo = classpath.irFiles map { irFile =>
PersistentState.getPersistentIRFile(irFile).info
persistentState.getPersistentIRFile(irFile).info
}
new Analyzer(logger, CoreData.CoreClassesInfo ++ userInfo)
}

private[this] object PersistentState {

val files = mutable.Map.empty[String, PersistentIRFile]
val encodedNameToPersistentFile =
mutable.Map.empty[String, PersistentIRFile]

var statsReused: Int = 0
var statsInvalidated: Int = 0
var statsTreesRead: Int = 0

def startRun(): Unit = {
statsReused = 0
statsInvalidated = 0
statsTreesRead = 0
for (file <- files.values)
file.startRun()
}

def getPersistentIRFile(irFile: VirtualScalaJSIRFile): PersistentIRFile = {
val file = files.getOrElseUpdate(irFile.path,
new PersistentIRFile(irFile.path))
if (file.updateFile(irFile))
statsReused += 1
else
statsInvalidated += 1
encodedNameToPersistentFile += ((file.info.encodedName, file))
file
}

def endRun(): Unit = {
// "Garbage-collect" persisted versions of files that have disappeared
files.retain((_, f) => f.cleanAfterRun())
encodedNameToPersistentFile.clear()
logger.debug(
s"Inc. opt stats: reused: $statsReused -- "+
s"invalidated: $statsInvalidated -- trees read: $statsTreesRead")
}
}

private def writeDCEedOutput(inputs: Inputs, outputConfig: OutputConfig,
analyzer: Analyzer): Unit = {

Expand Down Expand Up @@ -132,7 +100,7 @@ class ScalaJSOptimizer {
for {
classInfo <- analyzer.classInfos.values.toSeq.sortWith(compareClassInfo)
if classInfo.isNeededAtAll
persistentFile <- PersistentState.encodedNameToPersistentFile.get(
persistentFile <- persistentState.encodedNameToPersistentFile.get(
classInfo.encodedName)
} {
import ir.Trees._
Expand All @@ -141,7 +109,7 @@ class ScalaJSOptimizer {

val d = persistentFile.desugared
lazy val classDef = {
PersistentState.statsTreesRead += 1
persistentState.statsTreesRead += 1
persistentFile.tree
}

Expand Down Expand Up @@ -256,6 +224,41 @@ object ScalaJSOptimizer {

// Private helpers -----------------------------------------------------------

private final class PersistentState {
val files = mutable.Map.empty[String, PersistentIRFile]
val encodedNameToPersistentFile =
mutable.Map.empty[String, PersistentIRFile]

var statsReused: Int = 0
var statsInvalidated: Int = 0
var statsTreesRead: Int = 0

def startRun(): Unit = {
statsReused = 0
statsInvalidated = 0
statsTreesRead = 0
for (file <- files.values)
file.startRun()
}

def getPersistentIRFile(irFile: VirtualScalaJSIRFile): PersistentIRFile = {
val file = files.getOrElseUpdate(irFile.path,
new PersistentIRFile(irFile.path))
if (file.updateFile(irFile))
statsReused += 1
else
statsInvalidated += 1
encodedNameToPersistentFile += ((file.info.encodedName, file))
file
}

def endRun(): Unit = {
// "Garbage-collect" persisted versions of files that have disappeared
files.retain((_, f) => f.cleanAfterRun())
encodedNameToPersistentFile.clear()
}
}

private final class PersistentIRFile(val path: String) {
import ir.Trees._

Expand Down