Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code gen error handling: fail fast on throwable and print stack trace #113

Open
wants to merge 1 commit into
base: 2.13.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions src/compiler/scala/tools/nsc/backend/jvm/CodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package backend.jvm

import scala.collection.mutable.ListBuffer
import scala.tools.asm.tree.ClassNode
import scala.tools.nsc.util.stackTraceString

abstract class CodeGen[G <: Global](val global: G) extends PerRunInit {
val bTypes: BTypesFromSymbols[global.type]
Expand All @@ -34,24 +35,25 @@ abstract class CodeGen[G <: Global](val global: G) extends PerRunInit {
val generatedClasses = ListBuffer.empty[GeneratedClass]

def genClassDef(cd: ClassDef): Unit = try {
val sym = cd.symbol
val position = sym.pos
val fullSymbolName = sym.javaClassName
val mainClassNode = genClass(cd, unit)
generatedClasses += GeneratedClass(mainClassNode, fullSymbolName, position, isArtifact = false)
if (bTypes.isTopLevelModuleClass(sym)) {
if (sym.companionClass == NoSymbol) {
val mirrorClassNode = genMirrorClass(sym, unit)
generatedClasses += GeneratedClass(mirrorClassNode, fullSymbolName, position, isArtifact = true)
if (!frontendAccess.directBackendReporting.hasErrors) {
val sym = cd.symbol
val position = sym.pos
val fullSymbolName = sym.javaClassName
val mainClassNode = genClass(cd, unit)
generatedClasses += GeneratedClass(mainClassNode, fullSymbolName, position, isArtifact = false)
if (bTypes.isTopLevelModuleClass(sym)) {
if (sym.companionClass == NoSymbol) {
val mirrorClassNode = genMirrorClass(sym, unit)
generatedClasses += GeneratedClass(mirrorClassNode, fullSymbolName, position, isArtifact = true)
}
else
log(s"No mirror class for module with linked class: ${sym.fullName}")
}
else
log(s"No mirror class for module with linked class: ${sym.fullName}")
}
} catch {
case ex: InterruptedException => throw ex
case ex: Throwable =>
if (settings.debug) ex.printStackTrace()
globalError(s"Error while emitting ${unit.source}\n${ex.getMessage}")
globalError(cd.pos, s"Error while emitting ${unit.source}\n${stackTraceString(ex)}")
}

def genClassDefs(tree: Tree): Unit = tree match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,10 @@ private[jvm] object GeneratedClassHandler {
frontendAccess.withThreadLocalReporter(unitInPostProcess.bufferedReporting) {
// 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.sourceFile)
unitInPostProcess.takeClasses() foreach { cls =>
if (!frontendAccess.directBackendReporting.hasErrors) {
postProcessor.sendToDisk(cls, unitInPostProcess.sourceFile)
}
}
}
}
Expand Down
8 changes: 3 additions & 5 deletions src/compiler/scala/tools/nsc/backend/jvm/PostProcessor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ package scala.tools.nsc
package backend.jvm

import java.util.concurrent.ConcurrentHashMap

import scala.collection.mutable
import scala.reflect.internal.util.{NoPosition, Position, StringContextStripMarginOps}
import scala.reflect.internal.util.{Position, StringContextStripMarginOps}
import scala.reflect.io.AbstractFile
import scala.tools.asm.ClassWriter
import scala.tools.asm.tree.ClassNode
import scala.tools.nsc
import scala.tools.nsc.backend.jvm.analysis.BackendUtils
import scala.tools.nsc.backend.jvm.opt._

Expand Down Expand Up @@ -74,9 +74,7 @@ abstract class PostProcessor extends PerRunInit {
} catch {
case ex: InterruptedException => throw ex
case ex: Throwable =>
// TODO fail fast rather than continuing to write the rest of the class files?
if (frontendAccess.compilerSettings.debug) ex.printStackTrace()
backendReporting.error(NoPosition, s"Error while emitting $internalName\n${ex.getMessage}")
backendReporting.error(clazz.position, s"Error while emitting $internalName\n${nsc.util.stackTraceString(ex)}")
null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ object PostProcessorFrontendAccess {
def warning(pos: Position, message: String): Unit
def inform(message: String): Unit
def log(message: String): Unit
def hasErrors: Boolean
}

final class BufferingBackendReporting extends BackendReporting {
Expand All @@ -132,6 +133,10 @@ object PostProcessorFrontendAccess {
def log(message: String): Unit =
this.synchronized(bufferedReports ::= new ReportLog(message))

def hasErrors: Boolean = {
this.synchronized(bufferedReports.nonEmpty)
}

def relayReports(toReporting: BackendReporting): Unit = this.synchronized {
if (bufferedReports.nonEmpty) {
bufferedReports.reverse.foreach(_.relay(toReporting))
Expand Down Expand Up @@ -262,6 +267,8 @@ object PostProcessorFrontendAccess {
def log(message: String): Unit = frontendSynch {
global.log(message)
}

def hasErrors: Boolean = global.reporter.hasErrors
}
def unsafeStatistics: Statistics with BackendStats = global.statistics

Expand Down
4 changes: 2 additions & 2 deletions test/files/run/large_class.check
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: Error while emitting BigEnoughToFail
Class too large: BigEnoughToFail
newSource1.scala:1: error: Error while emitting BigEnoughToFail
scala.tools.asm.ClassTooLargeException: Class too large: BigEnoughToFail
6 changes: 5 additions & 1 deletion test/files/run/large_class.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import java.io.{ByteArrayOutputStream, PrintWriter}
import scala.tools.partest._

// a cold run of partest takes about 15s for this test on my laptop
Expand All @@ -19,8 +20,11 @@ object Test extends DirectTest {
|}""".stripMargin.trim

override def show(): Unit = {
Console.withErr(System.out) {
val baos = new ByteArrayOutputStream()
Console.withErr(baos) {
compile()
}
val out = baos.toString()
println(out.linesIterator.take(2).mkString("\n"))
}
}
4 changes: 2 additions & 2 deletions test/files/run/large_code.check
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: Error while emitting BigEnoughToFail
Method too large: BigEnoughToFail.tooLong ()V
newSource1.scala:1: error: Error while emitting BigEnoughToFail
scala.tools.asm.MethodTooLargeException: Method too large: BigEnoughToFail.tooLong ()V
6 changes: 5 additions & 1 deletion test/files/run/large_code.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import java.io.ByteArrayOutputStream
import scala.tools.partest._

// a cold run of partest takes about 15s for this test on my laptop
Expand All @@ -16,8 +17,11 @@ object Test extends DirectTest {
|}""".stripMargin.trim

override def show(): Unit = {
Console.withErr(System.out) {
val baos = new ByteArrayOutputStream()
Console.withErr(baos) {
compile()
}
val out = baos.toString()
println(out.linesIterator.take(2).mkString("\n"))
}
}