diff options
author | Miguel Garcia <miguelalfredo.garcia@epfl.ch> | 2013-08-21 17:42:25 +0200 |
---|---|---|
committer | Miguel Garcia <miguelalfredo.garcia@epfl.ch> | 2013-08-21 17:42:25 +0200 |
commit | cd1c070ec45cc91a2f3d08c2f190402f19b59f7e (patch) | |
tree | 449a58e7acb2fe2202e1c5f41f27eeb12f1fa8e2 /src | |
parent | 22d907c1e97a608063f94b87aff1279482e2e58a (diff) | |
download | scala-cd1c070ec45cc91a2f3d08c2f190402f19b59f7e.tar.gz scala-cd1c070ec45cc91a2f3d08c2f190402f19b59f7e.tar.bz2 scala-cd1c070ec45cc91a2f3d08c2f190402f19b59f7e.zip |
GenBCode: decouple ClassNode building from encoding as byte array
To recap from the previous commit, another baby step towards
pipelining of class building and class writing.
Implementing similar functionality in GenASM is up for grabs,
see https://issues.scala-lang.org/browse/SI-6164
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala | 86 |
1 files changed, 67 insertions, 19 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala index 6a2ba43f4c..b6ecc66b10 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala @@ -23,7 +23,10 @@ import scala.tools.asm * (a) an optional mirror class, * (b) a plain class, and * (c) an optional bean class. - * - each of the ClassNodes above is lowered into a byte-array (ie into a classfile) and serialized. + * - each of the items (a), (b), (c) is placed on queue `q2`. + * Those items will be transferred from that queue to `q3` by Worker2, + * whose job is lowering a ClassNode into a byte-array (ie into a classfile) + * - the classfilse are serialized in `drainQ3()` * * Plain, mirror, and bean classes are built respectively by PlainClassBuilder, JMirrorBuilder, and JBeanInfoBuilder. * @@ -52,6 +55,19 @@ abstract class GenBCode extends BCodeSyncAndTry { private var needsOutFolder = false // whether getOutFolder(claszSymbol) should be invoked for each claszSymbol + /* ---------------- q2 ---------------- */ + + case class Item2(arrivalPos: Int, + mirror: asm.tree.ClassNode, + plain: asm.tree.ClassNode, + bean: asm.tree.ClassNode, + outFolder: scala.tools.nsc.io.AbstractFile) { + def isPoison = { arrivalPos == Int.MaxValue } + } + + private val poison2 = Item2(Int.MaxValue, null, null, null, null) + private val q2 = new _root_.java.util.LinkedList[Item2] + /* ---------------- q3 ---------------- */ /* @@ -88,7 +104,8 @@ abstract class GenBCode extends BCodeSyncAndTry { /* * Checks for duplicate internal names case-insensitively, - * builds ASM ClassNodes for mirror, plain, and bean classes. + * builds ASM ClassNodes for mirror, plain, and bean classes; + * enqueues them in queue-2. * */ def visit(arrivalPos: Int, cd: ClassDef, cunit: CompilationUnit) { @@ -136,31 +153,60 @@ abstract class GenBCode extends BCodeSyncAndTry { // ----------- hand over to next pipeline - addToQ3(arrivalPos, + val item2 = + Item2(arrivalPos, mirrorC, plainC, beanC, outF) - } // end of method visit() + q2 add item2 // at the very end of this method so that no Worker2 thread starts mutating before we're done. - private def addToQ3(arrivalPos: Int, - mirror: asm.tree.ClassNode, - plain: asm.tree.ClassNode, - bean: asm.tree.ClassNode, - outFolder: scala.tools.nsc.io.AbstractFile) { + } // end of method visit() - def getByteArray(cn: asm.tree.ClassNode): Array[Byte] = { - val cw = new CClassWriter(extraProc) - cn.accept(cw) - cw.toByteArray + /* + * Pipeline that takes ClassNodes from queue-2. The unit of work depends on the optimization level: + * + * (a) no optimization involves: + * - converting the plain ClassNode to byte array and placing it on queue-3 + */ + class Worker2 { + + def run() { + while (true) { + val item = q2.poll + if (item.isPoison) { + q3 add poison3 + return + } + else { + try { addToQ3(item) } + catch { + case ex: Throwable => + ex.printStackTrace() + error(s"Error while emitting ${item.plain.name}\n${ex.getMessage}") + } + } + } } - 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)) + private def addToQ3(item: Item2) { - q3 add Item3(arrivalPos, mirrorC, plainC, beanC, outFolder) + def getByteArray(cn: asm.tree.ClassNode): Array[Byte] = { + val cw = new CClassWriter(extraProc) + cn.accept(cw) + cw.toByteArray + } - } + val Item2(arrivalPos, mirror, plain, bean, outFolder) = item + + 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)) + + q3 add Item3(arrivalPos, mirrorC, plainC, beanC, outFolder) + + } + + } // end of class BCodePhase.Worker2 var arrivalPos = 0 @@ -189,7 +235,8 @@ abstract class GenBCode extends BCodeSyncAndTry { needsOutFolder = bytecodeWriter.isInstanceOf[ClassBytecodeWriter] super.run() - q3 add poison3 + q2 add poison2 + (new Worker2).run() drainQ3() // closing output files. @@ -251,6 +298,7 @@ abstract class GenBCode extends BCodeSyncAndTry { } // we're done + assert(q2.isEmpty, s"Some classfiles remained in the second queue: $q2") assert(q3.isEmpty, s"Some classfiles weren't written to disk: $q3") } |