diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala | 62 |
1 files changed, 43 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 af962c4ce0..6593d4b725 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala @@ -14,6 +14,7 @@ import scala.reflect.internal.util.Statistics import scala.tools.asm import scala.tools.asm.tree.ClassNode +import scala.tools.nsc.backend.jvm.opt.ByteCodeRepository /* * Prepare in-memory representations of classfiles using the ASM Tree API, and serialize them to disk. @@ -76,15 +77,16 @@ abstract class GenBCode extends BCodeSyncAndTry { /* ---------------- q2 ---------------- */ - case class Item2(arrivalPos: Int, - mirror: asm.tree.ClassNode, - plain: asm.tree.ClassNode, - bean: asm.tree.ClassNode, - outFolder: scala.tools.nsc.io.AbstractFile) { + case class Item2(arrivalPos: Int, + mirror: asm.tree.ClassNode, + plain: asm.tree.ClassNode, + bean: asm.tree.ClassNode, + sourceFilePath: String, + outFolder: scala.tools.nsc.io.AbstractFile) { def isPoison = { arrivalPos == Int.MaxValue } } - private val poison2 = Item2(Int.MaxValue, null, null, null, null) + private val poison2 = Item2(Int.MaxValue, null, null, null, null, null) private val q2 = new _root_.java.util.LinkedList[Item2] /* ---------------- q3 ---------------- */ @@ -134,7 +136,7 @@ abstract class GenBCode extends BCodeSyncAndTry { return } else { - try { withCurrentUnit(item.cunit)(visit(item)) } + try { withCurrentUnitNoLog(item.cunit)(visit(item)) } catch { case ex: Throwable => ex.printStackTrace() @@ -186,7 +188,7 @@ abstract class GenBCode extends BCodeSyncAndTry { // -------------- "plain" class -------------- val pcb = new PlainClassBuilder(cunit) pcb.genPlainClass(cd) - val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName, cunit) else null; + val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisBType.internalName, cunit) else null val plainC = pcb.cnode // -------------- bean info class, if needed -------------- @@ -204,6 +206,7 @@ abstract class GenBCode extends BCodeSyncAndTry { val item2 = Item2(arrivalPos, mirrorC, plainC, beanC, + cunit.source.file.canonicalPath, outF) q2 add item2 // at the very end of this method so that no Worker2 thread starts mutating before we're done. @@ -220,17 +223,24 @@ abstract class GenBCode extends BCodeSyncAndTry { */ class Worker2 { def runGlobalOptimizations(): Unit = { - import scala.collection.convert.decorateAsScala._ - if (settings.YoptBuildCallGraph) { - q2.asScala foreach { - case Item2(_, _, plain, _, _) => - // skip mirror / bean: wd don't inline into tem, and they are not used in the plain class - if (plain != null) callGraph.addClass(plain) - } + import scala.collection.JavaConverters._ + + // add classes to the bytecode repo before building the call graph: the latter needs to + // look up classes and methods in the code repo. + if (settings.optAddToBytecodeRepository) q2.asScala foreach { + case Item2(_, mirror, plain, bean, sourceFilePath, _) => + val someSourceFilePath = Some(sourceFilePath) + if (mirror != null) byteCodeRepository.add(mirror, someSourceFilePath) + if (plain != null) byteCodeRepository.add(plain, someSourceFilePath) + if (bean != null) byteCodeRepository.add(bean, someSourceFilePath) + } + if (settings.optBuildCallGraph) q2.asScala foreach { item => + // skip call graph for mirror / bean: wd don't inline into tem, and they are not used in the plain class + if (item.plain != null) callGraph.addClass(item.plain) } - if (settings.YoptInlinerEnabled) + if (settings.optInlinerEnabled) bTypes.inliner.runInliner() - if (settings.YoptClosureElimination) + if (settings.optClosureInvocations) closureOptimizer.rewriteClosureApplyInvocations() } @@ -238,6 +248,11 @@ abstract class GenBCode extends BCodeSyncAndTry { BackendStats.timed(BackendStats.methodOptTimer)(localOpt.methodOptimizations(classNode)) } + def setInnerClasses(classNode: ClassNode): Unit = if (classNode != null) { + classNode.innerClasses.clear() + addInnerClasses(classNode, bTypes.backendUtils.collectNestedClasses(classNode)) + } + def run() { runGlobalOptimizations() @@ -250,8 +265,17 @@ abstract class GenBCode extends BCodeSyncAndTry { else { try { localOptimizations(item.plain) + setInnerClasses(item.plain) + val lambdaImplMethods = getIndyLambdaImplMethods(item.plain.name) + if (lambdaImplMethods.nonEmpty) + backendUtils.addLambdaDeserialize(item.plain, lambdaImplMethods) + setInnerClasses(item.mirror) + setInnerClasses(item.bean) addToQ3(item) } catch { + case e: java.lang.RuntimeException if e.getMessage != null && (e.getMessage contains "too large!") => + reporter.error(NoPosition, + s"Could not write class ${item.plain.name} because it exceeds JVM code size limits. ${e.getMessage}") case ex: Throwable => ex.printStackTrace() error(s"Error while emitting ${item.plain.name}\n${ex.getMessage}") @@ -268,7 +292,7 @@ abstract class GenBCode extends BCodeSyncAndTry { cw.toByteArray } - val Item2(arrivalPos, mirror, plain, bean, outFolder) = item + 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)) @@ -313,7 +337,7 @@ abstract class GenBCode extends BCodeSyncAndTry { bTypes.initializeCoreBTypes() bTypes.javaDefinedClasses.clear() bTypes.javaDefinedClasses ++= currentRun.symSource collect { - case (sym, _) if sym.isJavaDefined => sym.javaBinaryName.toString + case (sym, _) if sym.isJavaDefined => sym.javaBinaryNameString } Statistics.stopTimer(BackendStats.bcodeInitTimer, initStart) |