Skip to content

Commit 3fa2c97

Browse files
adriaanmAdriaan Moors
authored and
Adriaan Moors
committed
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.
1 parent 2aa9da5 commit 3fa2c97

File tree

4 files changed

+37
-6
lines changed

4 files changed

+37
-6
lines changed

src/asm/scala/tools/asm/MethodWriter.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1853,7 +1853,12 @@ final int getSize() {
18531853
int size = 8;
18541854
if (code.length > 0) {
18551855
if (code.length > 65536) {
1856-
throw new RuntimeException("Method code too large!");
1856+
String nameString = "";
1857+
int i = 0;
1858+
// find item that corresponds to the index of our name
1859+
while (i < cw.items.length && (cw.items[i] == null || cw.items[i].index != name)) i++;
1860+
if (cw.items[i] != null) nameString = cw.items[i].strVal1 +"'s ";
1861+
throw new RuntimeException("Method "+ nameString +"code too large!");
18571862
}
18581863
cw.newUTF8("Code");
18591864
size += 18 + code.length + 8 * handlerCount;

src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -450,17 +450,17 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
450450
}
451451

452452
// -----------------------------------------------------------------------------------------
453-
// utitilies useful when emitting plain, mirror, and beaninfo classes.
453+
// utilities useful when emitting plain, mirror, and beaninfo classes.
454454
// -----------------------------------------------------------------------------------------
455455

456456
def writeIfNotTooBig(label: String, jclassName: String, jclass: asm.ClassWriter, sym: Symbol) {
457457
try {
458458
val arr = jclass.toByteArray()
459459
bytecodeWriter.writeClass(label, jclassName, arr, sym)
460460
} catch {
461-
case e: java.lang.RuntimeException if(e.getMessage() == "Class file too large!") =>
462-
// TODO check where ASM throws the equivalent of CodeSizeTooBigException
463-
log("Skipped class "+jclassName+" because it exceeds JVM limits (it's too big or has methods that are too long).")
461+
case e: java.lang.RuntimeException if e != null && (e.getMessage contains "too large!") =>
462+
reporter.error(sym.pos,
463+
s"Could not write class $jclassName because it exceeds JVM code size limits. ${e.getMessage}")
464464
}
465465
}
466466

@@ -1402,7 +1402,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
14021402
addInnerClasses(clasz.symbol, jclass)
14031403
jclass.visitEnd()
14041404
writeIfNotTooBig("" + c.symbol.name, thisName, jclass, c.symbol)
1405-
14061405
}
14071406

14081407
/**

test/files/run/large_code.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
newSource1.scala:1: error: Could not write class BigEnoughToFail because it exceeds JVM code size limits. Method tooLong's code too large!
2+
class BigEnoughToFail {
3+
^

test/files/run/large_code.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import scala.tools.partest._
2+
import java.io.{Console => _, _}
3+
4+
// a cold run of partest takes about 15s for this test on my laptop
5+
object Test extends DirectTest {
6+
override def extraSettings: String = "-usejavacp -d " + testOutput.path
7+
8+
// test that we hit the code size limit and error out gracefully
9+
// 5958 is the magic number (2^16/11 -- each `a(1,2,3,4,5,6)` is 11 bytes of bytecode)
10+
override def code
11+
= s"""
12+
|class BigEnoughToFail {
13+
| def a(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int): Unit = {}
14+
| def tooLong: Unit = {
15+
| ${(1 to 5958) map (_ => "a(1,2,3,4,5,6)") mkString(";")}
16+
| }
17+
|}""".stripMargin.trim
18+
19+
override def show(): Unit = {
20+
Console.withErr(System.out) {
21+
compile()
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)