Created
February 19, 2018 08:26
-
-
Save lrytz/5b0db9dd3829bb15140f098161fe6fc5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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