diff options
3 files changed, 35 insertions, 91 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala index 42921e733d..ff68aba845 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala @@ -37,7 +37,7 @@ trait BytecodeWriters { getFile(outputDirectory(sym), clsName, suffix) trait BytecodeWriter { - def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile): Unit + def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol): Unit def close(): Unit = () } @@ -48,9 +48,7 @@ trait BytecodeWriters { ) val writer = new Jar(jfile).jarWriter(jarMainAttrs: _*) - def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) { - assert(outfile == null, - "The outfile formal param is there just because ClassBytecodeWriter overrides this method and uses it.") + def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) { val path = jclassName + ".class" val out = writer.newOutputStream(path) @@ -74,21 +72,21 @@ trait BytecodeWriters { try javap(Seq("-verbose", "dummy")) foreach (_.show()) finally pw.close() } - abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) { - super.writeClass(label, jclassName, jclassBytes, outfile) + abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) { + super.writeClass(label, jclassName, jclassBytes, sym) + val bytes = getFile(sym, jclassName, ".class").toByteArray val segments = jclassName.split("[./]") val javapFile = segments.foldLeft(baseDir: Path)(_ / _) changeExtension "javap" toFile; javapFile.parent.createDirectory() - emitJavap(jclassBytes, javapFile) + emitJavap(bytes, javapFile) } } trait ClassBytecodeWriter extends BytecodeWriter { - def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) { - assert(outfile != null, - "Precisely this override requires its invoker to hand out a non-null AbstractFile.") + def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) { + val outfile = getFile(sym, jclassName, ".class") val outstream = new DataOutputStream(outfile.bufferedOutput) try outstream.write(jclassBytes, 0, jclassBytes.length) @@ -100,8 +98,8 @@ trait BytecodeWriters { trait DumpBytecodeWriter extends BytecodeWriter { val baseDir = Directory(settings.Ydumpclasses.value).createDirectory() - abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) { - super.writeClass(label, jclassName, jclassBytes, outfile) + abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) { + super.writeClass(label, jclassName, jclassBytes, sym) val pathName = jclassName var dumpFile = pathName.split("[./]").foldLeft(baseDir: Path) (_ / _) changeExtension "class" toFile; diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 32c100b026..ac2780f53e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -29,10 +29,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { val phaseName = "jvm"
- case class WorkUnit(label: String, jclassName: String, jclass: asm.ClassWriter, outF: AbstractFile)
-
- type WorkUnitQueue = _root_.java.util.concurrent.LinkedBlockingQueue[WorkUnit]
-
/** Create a new phase */
override def newPhase(p: Phase): Phase = new AsmPhase(p)
@@ -152,44 +148,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { }
}
- // -----------------------------------------------------------------------------------------
- // Allow overlapping disk write of classfiles with building of the next classfiles.
- // -----------------------------------------------------------------------------------------
-
- val q = new WorkUnitQueue(500)
-
- class WriteTask(bytecodeWriter: BytecodeWriter) extends _root_.java.lang.Runnable {
-
- def run() {
- var stop = false
- try {
- while (!stop) {
- val WorkUnit(label, jclassName, jclass, outF) = q.take
- if(jclass eq null) { stop = true }
- else { writeIfNotTooBig(label, jclassName, jclass, outF) }
- }
- } catch {
- case ex: InterruptedException => throw ex
- }
- }
-
- private def writeIfNotTooBig(label: String, jclassName: String, jclass: asm.ClassWriter, outF: AbstractFile) {
- try {
- val arr = jclass.toByteArray()
- bytecodeWriter.writeClass(label, jclassName, arr, outF)
- } catch {
- case e: java.lang.RuntimeException if(e.getMessage() == "Class file too large!") =>
- // TODO check where ASM throws the equivalent of CodeSizeTooBigException
- log("Skipped class "+jclassName+" because it exceeds JVM limits (it's too big or has methods that are too long).")
- }
- }
-
- }
-
- // -----------------------------------------------------------------------------------------
- // what AsmPhase does.
- // -----------------------------------------------------------------------------------------
-
override def run() {
if (settings.debug.value)
@@ -203,14 +161,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters { var sortedClasses = classes.values.toList sortBy ("" + _.symbol.fullName)
debuglog("Created new bytecode generator for " + classes.size + " classes.")
- val bytecodeWriter = initBytecodeWriter(sortedClasses filter isJavaEntryPoint)
- val needsOutfileForSymbol = bytecodeWriter.isInstanceOf[ClassBytecodeWriter]
-
- val plainCodeGen = new JPlainBuilder(q, needsOutfileForSymbol)
- val mirrorCodeGen = new JMirrorBuilder(q, needsOutfileForSymbol)
- val beanInfoCodeGen = new JBeanInfoBuilder(q, needsOutfileForSymbol)
-
- new _root_.java.lang.Thread(new WriteTask(bytecodeWriter)).start()
+ val bytecodeWriter = initBytecodeWriter(sortedClasses filter isJavaEntryPoint)
+ val plainCodeGen = new JPlainBuilder(bytecodeWriter)
+ val mirrorCodeGen = new JMirrorBuilder(bytecodeWriter)
+ val beanInfoCodeGen = new JBeanInfoBuilder(bytecodeWriter)
while(!sortedClasses.isEmpty) {
val c = sortedClasses.head
@@ -233,10 +187,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { classes -= c.symbol // GC opportunity
}
- q put WorkUnit(null, null, null, null)
-
- while(!q.isEmpty) { _root_.java.lang.Thread.sleep(10) }
-
bytecodeWriter.close()
classes.clear()
reverseJavaName.clear()
@@ -498,7 +448,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { val JAVA_LANG_STRING = asm.Type.getObjectType("java/lang/String")
/** basic functionality for class file building */
- abstract class JBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean) {
+ abstract class JBuilder(bytecodeWriter: BytecodeWriter) {
val EMPTY_JTYPE_ARRAY = Array.empty[asm.Type]
val EMPTY_STRING_ARRAY = Array.empty[String]
@@ -554,6 +504,17 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // utitilies useful when emitting plain, mirror, and beaninfo classes.
// -----------------------------------------------------------------------------------------
+ def writeIfNotTooBig(label: String, jclassName: String, jclass: asm.ClassWriter, sym: Symbol) {
+ try {
+ val arr = jclass.toByteArray()
+ bytecodeWriter.writeClass(label, jclassName, arr, sym)
+ } catch {
+ case e: java.lang.RuntimeException if(e.getMessage() == "Class file too large!") =>
+ // TODO check where ASM throws the equivalent of CodeSizeTooBigException
+ log("Skipped class "+jclassName+" because it exceeds JVM limits (it's too big or has methods that are too long).")
+ }
+ }
+
/** Specialized array conversion to prevent calling
* java.lang.reflect.Array.newInstance via TraversableOnce.toArray
*/
@@ -767,18 +728,11 @@ abstract class GenASM extends SubComponent with BytecodeWriters { }
}
- def enqueue(label: String, jclassName: String, jclass: asm.ClassWriter, sym: Symbol) {
- val outF: scala.tools.nsc.io.AbstractFile = {
- if(needsOutfileForSymbol) getFile(sym, jclassName, ".class") else null
- }
- wuQ put WorkUnit(label, jclassName, jclass, outF)
- }
-
} // end of class JBuilder
/** functionality for building plain and mirror classes */
- abstract class JCommonBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean) extends JBuilder(wuQ, needsOutfileForSymbol) {
+ abstract class JCommonBuilder(bytecodeWriter: BytecodeWriter) extends JBuilder(bytecodeWriter) {
def debugLevel = settings.debuginfo.indexOfChoice
@@ -1342,8 +1296,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters { case class BlockInteval(start: BasicBlock, end: BasicBlock)
/** builder of plain classes */
- class JPlainBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean)
- extends JCommonBuilder(wuQ, needsOutfileForSymbol)
+ class JPlainBuilder(bytecodeWriter: BytecodeWriter)
+ extends JCommonBuilder(bytecodeWriter)
with JAndroidBuilder {
val MIN_SWITCH_DENSITY = 0.7
@@ -1499,7 +1453,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { addInnerClasses(clasz.symbol, jclass)
jclass.visitEnd()
- enqueue("" + c.symbol.name, thisName, jclass, c.symbol)
+ writeIfNotTooBig("" + c.symbol.name, thisName, jclass, c.symbol)
}
@@ -2938,7 +2892,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { /** builder of mirror classes */
- class JMirrorBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean) extends JCommonBuilder(wuQ, needsOutfileForSymbol) {
+ class JMirrorBuilder(bytecodeWriter: BytecodeWriter) extends JCommonBuilder(bytecodeWriter) {
private var cunit: CompilationUnit = _
def getCurrentCUnit(): CompilationUnit = cunit;
@@ -2984,7 +2938,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { addInnerClasses(modsym, mirrorClass)
mirrorClass.visitEnd()
- enqueue("" + modsym.name, mirrorName, mirrorClass, modsym)
+ writeIfNotTooBig("" + modsym.name, mirrorName, mirrorClass, modsym)
}
@@ -2992,7 +2946,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { /** builder of bean info classes */
- class JBeanInfoBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean) extends JBuilder(wuQ, needsOutfileForSymbol) {
+ class JBeanInfoBuilder(bytecodeWriter: BytecodeWriter) extends JBuilder(bytecodeWriter) {
/**
* Generate a bean info class that describes the given class.
@@ -3113,7 +3067,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { addInnerClasses(clasz.symbol, beanInfoClass)
beanInfoClass.visitEnd()
- enqueue("BeanInfo ", beanInfoName, beanInfoClass, clasz.symbol)
+ writeIfNotTooBig("BeanInfo ", beanInfoName, beanInfoClass, clasz.symbol)
}
} // end of class JBeanInfoBuilder
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index ad054015ef..21260d399c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -183,6 +183,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with class BytecodeGenerator(bytecodeWriter: BytecodeWriter) extends BytecodeUtil { def this() = this(new ClassBytecodeWriter { }) def debugLevel = settings.debuginfo.indexOfChoice + import bytecodeWriter.writeClass val MIN_SWITCH_DENSITY = 0.7 val INNER_CLASSES_FLAGS = @@ -343,15 +344,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with writeClass("" + sym.name, jclass.getName(), toByteArray(jclass), sym) } - val needsOutfileForSymbol = bytecodeWriter.isInstanceOf[ClassBytecodeWriter] - - def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) { - val outF: scala.tools.nsc.io.AbstractFile = { - if(needsOutfileForSymbol) getFile(sym, jclassName, ".class") else null - } - bytecodeWriter.writeClass(label, jclassName, jclassBytes, outF) - } - /** Returns the ScalaSignature annotation if it must be added to this class, * none otherwise; furthermore, it adds to `jclass` the ScalaSig marker * attribute (marking that a scala signature annotation is present) or the |