summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
diff options
context:
space:
mode:
authorMiguel Garcia <miguelalfredo.garcia@epfl.ch>2013-08-21 17:22:07 +0200
committerMiguel Garcia <miguelalfredo.garcia@epfl.ch>2013-08-21 17:22:07 +0200
commit22d907c1e97a608063f94b87aff1279482e2e58a (patch)
treec650c7d87265815927af9011999d5beceb48f04d /src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
parent2a659cf0edb897e0e18c1604c1ec5950b623827a (diff)
downloadscala-22d907c1e97a608063f94b87aff1279482e2e58a.tar.gz
scala-22d907c1e97a608063f94b87aff1279482e2e58a.tar.bz2
scala-22d907c1e97a608063f94b87aff1279482e2e58a.zip
GenBCode: decouple ClassNode building from classfile writing
This commit and two follow-up commits (recognizable because of the starting words "decouple this from that" in the commit message) are baby steps towards pipelining of class building and class writing, ie allowing class building (which requires typer) and "the rest" which doesn't) to run in parallel. The commits have been broken up following a previous review comment.
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala108
1 files changed, 90 insertions, 18 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index e55a3baed0..6a2ba43f4c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -52,6 +52,38 @@ abstract class GenBCode extends BCodeSyncAndTry {
private var needsOutFolder = false // whether getOutFolder(claszSymbol) should be invoked for each claszSymbol
+ /* ---------------- q3 ---------------- */
+
+ /*
+ * An item of queue-3 (the last queue before serializing to disk) contains three of these
+ * (one for each of mirror, plain, and bean classes).
+ *
+ * @param jclassName internal name of the class
+ * @param jclassBytes bytecode emitted for the class SubItem3 represents
+ */
+ case class SubItem3(
+ jclassName: String,
+ jclassBytes: Array[Byte]
+ )
+
+ case class Item3(arrivalPos: Int,
+ mirror: SubItem3,
+ plain: SubItem3,
+ bean: SubItem3,
+ outFolder: scala.tools.nsc.io.AbstractFile) {
+
+ def isPoison = { arrivalPos == Int.MaxValue }
+ }
+ private val i3comparator = new java.util.Comparator[Item3] {
+ override def compare(a: Item3, b: Item3) = {
+ if (a.arrivalPos < b.arrivalPos) -1
+ else if (a.arrivalPos == b.arrivalPos) 0
+ else 1
+ }
+ }
+ private val poison3 = Item3(Int.MaxValue, null, null, null, null)
+ private val q3 = new java.util.PriorityQueue[Item3](1000, i3comparator)
+
val caseInsensitively = mutable.Map.empty[String, Symbol]
/*
@@ -102,7 +134,19 @@ abstract class GenBCode extends BCodeSyncAndTry {
)
} else null
- // ----------- serialize classfiles to disk
+ // ----------- hand over to next pipeline
+
+ addToQ3(arrivalPos,
+ mirrorC, plainC, beanC,
+ outF)
+
+ } // end of method visit()
+
+ private def addToQ3(arrivalPos: Int,
+ mirror: asm.tree.ClassNode,
+ plain: asm.tree.ClassNode,
+ bean: asm.tree.ClassNode,
+ outFolder: scala.tools.nsc.io.AbstractFile) {
def getByteArray(cn: asm.tree.ClassNode): Array[Byte] = {
val cw = new CClassWriter(extraProc)
@@ -110,15 +154,13 @@ abstract class GenBCode extends BCodeSyncAndTry {
cw.toByteArray
}
- if (mirrorC != null) {
- sendToDisk(mirrorC.name, getByteArray(mirrorC), outF)
- }
- sendToDisk(plainC.name, getByteArray(plainC), outF)
- if (beanC != null) {
- sendToDisk(beanC.name, getByteArray(beanC), outF)
- }
+ val mirrorC = if (mirror == null) null else SubItem3(mirror.name, getByteArray(mirror))
+ val plainC = SubItem3(plain.name, getByteArray(plain))
+ val beanC = if (bean == null) null else SubItem3(bean.name, getByteArray(bean))
- } // end of method visit()
+ q3 add Item3(arrivalPos, mirrorC, plainC, beanC, outFolder)
+
+ }
var arrivalPos = 0
@@ -147,6 +189,8 @@ abstract class GenBCode extends BCodeSyncAndTry {
needsOutFolder = bytecodeWriter.isInstanceOf[ClassBytecodeWriter]
super.run()
+ q3 add poison3
+ drainQ3()
// closing output files.
bytecodeWriter.close()
@@ -170,17 +214,45 @@ abstract class GenBCode extends BCodeSyncAndTry {
clearBCodeTypes()
}
- def sendToDisk(jclassName: String, jclassBytes: Array[Byte], outFolder: _root_.scala.tools.nsc.io.AbstractFile) {
- try {
- val outFile =
- if (outFolder == null) null
- else getFileForClassfile(outFolder, jclassName, ".class")
- bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, outFile)
+ /* Pipeline that writes classfile representations to disk. */
+ private def drainQ3() {
+
+ def sendToDisk(cfr: SubItem3, outFolder: scala.tools.nsc.io.AbstractFile) {
+ if (cfr != null){
+ val SubItem3(jclassName, jclassBytes) = cfr
+ try {
+ val outFile =
+ if (outFolder == null) null
+ else getFileForClassfile(outFolder, jclassName, ".class")
+ bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, outFile)
+ }
+ catch {
+ case e: FileConflictException =>
+ error(s"error writing $jclassName: ${e.getMessage}")
+ }
+ }
}
- catch {
- case e: FileConflictException =>
- error(s"error writing $jclassName: ${e.getMessage}")
+
+ var moreComing = true
+ // `expected` denotes the arrivalPos whose Item3 should be serialized next
+ var expected = 0
+
+ while (moreComing) {
+ val incoming = q3.poll
+ moreComing = !incoming.isPoison
+ if (moreComing) {
+ val item = incoming
+ val outFolder = item.outFolder
+ sendToDisk(item.mirror, outFolder)
+ sendToDisk(item.plain, outFolder)
+ sendToDisk(item.bean, outFolder)
+ expected += 1
+ }
}
+
+ // we're done
+ assert(q3.isEmpty, s"Some classfiles weren't written to disk: $q3")
+
}
override def apply(cunit: CompilationUnit): Unit = {