Skip to content

Instantly share code, notes, and snippets.

@lrytz
Created February 19, 2018 08:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lrytz/5b0db9dd3829bb15140f098161fe6fc5 to your computer and use it in GitHub Desktop.
Save lrytz/5b0db9dd3829bb15140f098161fe6fc5 to your computer and use it in GitHub Desktop.
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/ClassfileWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/ClassfileWriters.scala
index 08f2d64778..125a343de7 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/ClassfileWriters.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/ClassfileWriters.scala
@@ -10,7 +10,7 @@ import java.util
import java.util.concurrent.ConcurrentHashMap
import java.util.zip.{CRC32, Deflater, ZipEntry, ZipOutputStream}
-import scala.reflect.internal.util.NoPosition
+import scala.reflect.internal.util.{NoPosition, Statistics}
import scala.tools.nsc.Global
import scala.tools.nsc.backend.jvm.BTypes.InternalName
import scala.tools.nsc.io.AbstractFile
@@ -83,7 +83,7 @@ abstract class ClassfileWriters {
}
val enableStats = statistics.enabled && settings.YaddBackendThreads.value == 1
- if (enableStats) new WithStatsWriter(withAdditionalFormats) else withAdditionalFormats
+ if (enableStats) new WithStatsWriter(statistics, withAdditionalFormats) else withAdditionalFormats
}
/**
@@ -257,12 +257,12 @@ abstract class ClassfileWriters {
}
}
- private final class WithStatsWriter(underlying: ClassfileWriter) extends ClassfileWriter {
+ private final class WithStatsWriter(statistics: Statistics with Global#GlobalStats, underlying: ClassfileWriter)
+ extends ClassfileWriter {
override def write(className: InternalName, bytes: Array[Byte], paths: CompilationUnitPaths): Unit = {
- val stats = frontendAccess.unsafeStatistics
- val snap = stats.startTimer(stats.bcodeWriteTimer)
+ val snap = statistics.startTimer(statistics.bcodeWriteTimer)
underlying.write(className, bytes, paths)
- stats.stopTimer(stats.bcodeWriteTimer, snap)
+ statistics.stopTimer(statistics.bcodeWriteTimer, snap)
}
override def close(): Unit = underlying.close()
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GeneratedClassHandler.scala b/src/compiler/scala/tools/nsc/backend/jvm/GeneratedClassHandler.scala
index ccecaf0e8d..1b4e948354 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GeneratedClassHandler.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GeneratedClassHandler.scala
@@ -48,7 +48,7 @@ private[jvm] object GeneratedClassHandler {
case maxThreads =>
if (global.statistics.enabled)
- global.reporter.warning(global.NoPosition, "jvm statistics are disabled with multi-threaded jvm class writing")
+ global.reporter.warning(global.NoPosition, "jvm statistics are not reliable with multi-threaded jvm class writing")
val additionalThreads = maxThreads - 1
// The thread pool queue is limited in size. When it's full, the `CallerRunsPolicy` causes
// a new task to be executed on the main thread, which provides back-pressure.
@@ -87,18 +87,16 @@ private[jvm] object GeneratedClassHandler {
override def toString: String = s"GloballyOptimising[$underlying]"
}
- sealed abstract class WritingClassHandler extends GeneratedClassHandler {
+ sealed abstract class WritingClassHandler(val javaExecutor: Executor) extends GeneratedClassHandler {
import postProcessor.bTypes.frontendAccess
- val javaExecutor: Executor
-
def tryStealing: Option[Runnable]
private val processingUnits = ListBuffer.empty[CompilationUnitInPostProcess]
def process(unit: GeneratedCompilationUnit): Unit = {
- val paths = CompilationUnitPaths(unit.sourceFile, frontendAccess.compilerSettings.outputDirectory(unit.sourceFile))
- val unitInPostProcess = new CompilationUnitInPostProcess(unit.classes, paths)
+ val unitInPostProcess = new CompilationUnitInPostProcess(unit.classes, unit.sourceFile,
+ frontendAccess.compilerSettings.outputDirectory(unit.sourceFile))
postProcessUnit(unitInPostProcess)
processingUnits += unitInPostProcess
}
@@ -111,7 +109,7 @@ private[jvm] object GeneratedClassHandler {
// we 'take' classes to reduce the memory pressure
// as soon as the class is consumed and written, we release its data
unitInPostProcess.takeClasses() foreach {
- postProcessor.sendToDisk(_, unitInPostProcess.paths)
+ postProcessor.sendToDisk(_, unitInPostProcess)
}
}
}
@@ -157,22 +155,22 @@ private[jvm] object GeneratedClassHandler {
} catch {
case NonFatal(t) =>
t.printStackTrace()
- frontendAccess.backendReporting.error(NoPosition, s"unable to write ${unitInPostProcess.paths.sourceFile} $t")
+ frontendAccess.backendReporting.error(NoPosition, s"unable to write ${unitInPostProcess.sourceFile} $t")
}
}
}
}
- private final class SyncWritingClassHandler(val postProcessor: PostProcessor) extends WritingClassHandler {
- val javaExecutor: Executor = (r) => r.run()
+ private final class SyncWritingClassHandler(val postProcessor: PostProcessor)
+ extends WritingClassHandler((r) => r.run()) {
override def toString: String = s"SyncWriting"
def tryStealing: Option[Runnable] = None
}
- private final class AsyncWritingClassHandler(val postProcessor: PostProcessor, val javaExecutor: ThreadPoolExecutor)
- extends WritingClassHandler {
+ private final class AsyncWritingClassHandler(val postProcessor: PostProcessor, override val javaExecutor: ThreadPoolExecutor)
+ extends WritingClassHandler(javaExecutor) {
override def toString: String = s"AsyncWriting[additional threads:${javaExecutor.getMaximumPoolSize}]"
@@ -187,7 +185,9 @@ private[jvm] object GeneratedClassHandler {
}
/** Paths for a compilation unit, used during classfile writing */
-final case class CompilationUnitPaths(sourceFile: AbstractFile, outputDir: AbstractFile) {
+sealed trait CompilationUnitPaths {
+ val sourceFile: AbstractFile
+ val outputDir: AbstractFile
def outputPath: Path = outputDir.file.toPath // `toPath` caches its result
}
@@ -197,7 +197,10 @@ final case class CompilationUnitPaths(sourceFile: AbstractFile, outputDir: Abstr
* - Keeps a reference to the future that runs the post-processor
* - Buffers messages reported during post-processing
*/
-final class CompilationUnitInPostProcess(private var classes: List[GeneratedClass], val paths: CompilationUnitPaths) {
+final class CompilationUnitInPostProcess(
+ private var classes: List[GeneratedClass],
+ val sourceFile: AbstractFile,
+ val outputDir: AbstractFile) extends CompilationUnitPaths {
def takeClasses(): List[GeneratedClass] = {
val c = classes
classes = Nil
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/PostProcessor.scala b/src/compiler/scala/tools/nsc/backend/jvm/PostProcessor.scala
index fbaea7f5f0..86eeecdbe7 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/PostProcessor.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/PostProcessor.scala
@@ -3,7 +3,7 @@ package backend.jvm
import java.util.concurrent.ConcurrentHashMap
-import scala.reflect.internal.util.{NoPosition, Position}
+import scala.reflect.internal.util.{NoPosition, Position, SourceFile, Statistics}
import scala.reflect.io.AbstractFile
import scala.tools.asm.ClassWriter
import scala.tools.asm.tree.ClassNode
@@ -109,12 +109,8 @@ abstract class PostProcessor extends PerRunInit {
}
def localOptimizations(classNode: ClassNode): Unit = {
- if (frontendAccess.compilerSettings.backendThreads > 1)
- localOpt.methodOptimizations(classNode)
- else {
- val stats = frontendAccess.unsafeStatistics
- stats.timed(stats.methodOptTimer)(localOpt.methodOptimizations(classNode))
- }
+ val stats = frontendAccess.unsafeStatistics
+ stats.timed(stats.methodOptTimer)(localOpt.methodOptimizations(classNode))
}
def setInnerClasses(classNode: ClassNode): Unit = {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/PostProcessorFrontendAccess.scala b/src/compiler/scala/tools/nsc/backend/jvm/PostProcessorFrontendAccess.scala
index 782aae3d5f..317b2873e0 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/PostProcessorFrontendAccess.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/PostProcessorFrontendAccess.scala
@@ -51,8 +51,6 @@ object PostProcessorFrontendAccess {
def outputDirectory(source: AbstractFile): AbstractFile
- def backendThreads: Int
-
def optAddToBytecodeRepository: Boolean
def optBuildCallGraph: Boolean
@@ -91,7 +89,7 @@ object PostProcessorFrontendAccess {
def log(message: String): Unit
}
- class BufferingBackendReporting extends BackendReporting {
+ final class BufferingBackendReporting extends BackendReporting {
// We optimise access to the buffered reports for the common case - that there are no warning/errors to report
// We could use a listBuffer etc - but that would be extra allocation in the common case
// Note - all access is externally synchronized, as this allow the reports to be generated in on thread and
@@ -173,8 +171,6 @@ object PostProcessorFrontendAccess {
// the call to `outputDirFor` should be frontendSynch'd, but we assume that the setting is not mutated during the backend
def outputDirectory(source: AbstractFile): AbstractFile = singleOutDir.getOrElse(s.outputDirs.outputDirFor(source))
- val backendThreads: Int = s.YaddBackendThreads.value
-
val optAddToBytecodeRepository: Boolean = s.optAddToBytecodeRepository
val optBuildCallGraph: Boolean = s.optBuildCallGraph
@@ -244,7 +240,6 @@ object PostProcessorFrontendAccess {
global.log(message)
}
}
-
def unsafeStatistics: Statistics with BackendStats = global.statistics
private lazy val cp = perRunLazy(this)(frontendSynch(optimizerClassPath(classPath)))
diff --git a/test/files/run/t5717.scala b/test/files/run/t5717.scala
index 1426eccc62..880d3c8e91 100644
--- a/test/files/run/t5717.scala
+++ b/test/files/run/t5717.scala
@@ -19,9 +19,9 @@ object Test extends StoreReporterDirectTest {
compileCode("package a { class B }")
val List(i) = filteredInfos
// for some reason, nio doesn't throw the same exception on windows and linux/mac
- val expected =
- if (util.Properties.isWin) "error writing a/B: Can't create directory \\a"
- else "error writing a/B: Can't create directory /a"
+ val path = if(util.Properties.isWin)"\\a" else "/a"
+ val expected = "error writing a/B: Can't create directory " + path +
+ "; there is an existing (non-directory) file in its path"
val actual = i.msg.replace(testOutput.path, "")
assert(actual == expected, actual)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment