Permalink
Browse files

Report error on code size overflow, log method name.

We used to silently skip class files that would exceed the JVM's size limits.
While rare, this should still be an error.

While I was at it, also included the name of the offending method.
  • Loading branch information...
1 parent 2aa9da5 commit 3fa2c97853de2110227f50982187b4377b8772bc @adriaanm adriaanm committed with Adriaan Moors Dec 12, 2013
@@ -1853,7 +1853,12 @@ final int getSize() {
int size = 8;
if (code.length > 0) {
if (code.length > 65536) {
- throw new RuntimeException("Method code too large!");
+ String nameString = "";
+ int i = 0;
+ // find item that corresponds to the index of our name
+ while (i < cw.items.length && (cw.items[i] == null || cw.items[i].index != name)) i++;
+ if (cw.items[i] != null) nameString = cw.items[i].strVal1 +"'s ";
+ throw new RuntimeException("Method "+ nameString +"code too large!");
}
cw.newUTF8("Code");
size += 18 + code.length + 8 * handlerCount;
@@ -450,17 +450,17 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}
// -----------------------------------------------------------------------------------------
- // utitilies useful when emitting plain, mirror, and beaninfo classes.
+ // utilities 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).")
+ case e: java.lang.RuntimeException if e != null && (e.getMessage contains "too large!") =>
+ reporter.error(sym.pos,
+ s"Could not write class $jclassName because it exceeds JVM code size limits. ${e.getMessage}")
}
}
@@ -1402,7 +1402,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
addInnerClasses(clasz.symbol, jclass)
jclass.visitEnd()
writeIfNotTooBig("" + c.symbol.name, thisName, jclass, c.symbol)
-
}
/**
@@ -0,0 +1,3 @@
+newSource1.scala:1: error: Could not write class BigEnoughToFail because it exceeds JVM code size limits. Method tooLong's code too large!
+class BigEnoughToFail {
+ ^
@@ -0,0 +1,24 @@
+import scala.tools.partest._
+import java.io.{Console => _, _}
+
+// a cold run of partest takes about 15s for this test on my laptop
+object Test extends DirectTest {
+ override def extraSettings: String = "-usejavacp -d " + testOutput.path
+
+ // test that we hit the code size limit and error out gracefully
+ // 5958 is the magic number (2^16/11 -- each `a(1,2,3,4,5,6)` is 11 bytes of bytecode)
+ override def code
+ = s"""
+ |class BigEnoughToFail {
+ | def a(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int): Unit = {}
+ | def tooLong: Unit = {
+ | ${(1 to 5958) map (_ => "a(1,2,3,4,5,6)") mkString(";")}
+ | }
+ |}""".stripMargin.trim
+
+ override def show(): Unit = {
+ Console.withErr(System.out) {
+ compile()
+ }
+ }
+}

0 comments on commit 3fa2c97

Please sign in to comment.