Skip to content

Commit

Permalink
Merge pull request #939 from retronym/faster/classes-in-jar
Browse files Browse the repository at this point in the history
Optimize knownProducts for direct-to-JAR compilation
  • Loading branch information
eed3si9n authored Nov 9, 2020
2 parents 206d9bc + 0ed5242 commit 6bcaba0
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,24 @@ object JarUtils {
* "C:\develop\zinc\target\output.jar!sbt\internal\inc\Compile.class"
*/
class ClassInJar(override val toString: String) extends AnyVal {
def toClassFilePath: Option[ClassFilePath] = splitJarReference._2
def toClassFilePath: Option[ClassFilePath] = Option(toClassFilePathOrNull)
def toClassFilePathOrNull: ClassFilePath = {
val idx = toString.indexOf('!')
if (idx < 0) null
else toClassFilePath(idx)
}
def splitJarReference: (File, Option[ClassFilePath]) = {
if (toString.contains("!")) {
val Array(jar, cls) = toString.split("!")
// ClassInJar stores RelClass part with File.separatorChar, however actual paths in zips always use '/'
val classFilePath = cls.replace('\\', '/')
(new File(jar), Some(classFilePath))
} else {
val idx = toString.indexOf('!')
if (idx < 0) {
(new File(toString), None)
} else {
(new File(toString.substring(0, idx)), Some(toClassFilePath(idx)))
}
}
private def toClassFilePath(idx: Int): String = {
// ClassInJar stores RelClass part with File.separatorChar, however actual paths in zips always use '/'
toString.substring(idx + 1).replace('\\', '/')
}

/**
* Wraps the string value inside a java.io.File object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import sbt.util.{ InterfaceUtil, Level, Logger }
import sbt.util.InterfaceUtil.{ jo2o, t2 }
import scala.collection.JavaConverters._
import scala.util.control.NonFatal
import scala.collection.parallel.immutable.ParVector
import xsbti.{ FileConverter, Position, Problem, Severity, UseScope, VirtualFile, VirtualFileRef }
import xsbt.api.{ APIUtil, HashAPI, NameHashing }
import xsbti.api._
Expand Down Expand Up @@ -1086,28 +1085,27 @@ private final class AnalysisCallback(

private def knownProducts(merged: Analysis) = {
// List classes defined in the files that were compiled in this run.
val ps = java.util.concurrent.ConcurrentHashMap.newKeySet[String]
val knownProducts: ParVector[VirtualFileRef] =
new ParVector(merged.relations.allSources.toVector)
.flatMap(merged.relations.products)
// extract product paths in parallel
jo2o(output.getSingleOutputAsPath) match {
case Some(so) if so.getFileName.toString.endsWith(".jar") =>
knownProducts foreach { product =>
new JarUtils.ClassInJar(product.id).toClassFilePath foreach { path =>
val ps: java.util.Set[String] = new java.util.HashSet[String]()
val knownProducts: collection.Set[VirtualFileRef] = merged.relations.allProducts

// extract product paths
val so = jo2o(output.getSingleOutputAsPath).getOrElse(sys.error(s"unsupported output $output"))
val isJarOutput = so.getFileName.toString.endsWith(".jar")
knownProducts foreach { product =>
if (isJarOutput) {
new JarUtils.ClassInJar(product.id).toClassFilePathOrNull match {
case null =>
case path =>
ps.add(path.replace('\\', '/'))
}
}
case Some(so) =>
knownProducts foreach { product =>
val productPath = converter.toPath(product)
try {
ps.add(so.relativize(productPath).toString.replace('\\', '/'))
} catch {
case NonFatal(_) => ps.add(product.id)
}
} else {
val productPath = converter.toPath(product)
try {
ps.add(so.relativize(productPath).toString.replace('\\', '/'))
} catch {
case NonFatal(_) => ps.add(product.id)
}
case _ => sys.error(s"unsupported output $output")
}
}
ps
}
Expand Down

0 comments on commit 6bcaba0

Please sign in to comment.