Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

SI-6546 InnerClasses attribute refers to absent class

At issue is that the optimizer would eliminate closure classes
completely, then neglect to eliminate those classes from the
container's InnerClasses attribute. This breaks tooling which
expects those entries to correspond to real classes.

The code change is essentially mgarcia's - I minimized it and
put the caches in perRunCaches, and added the test case which
verifies that after being compiled under -optimise, there are
no inner classes. Before/after:

  7,8d6
  <   InnerClasses:
  <        public final #22; //class A_1$$anonfun$f$1
  37,45c35,40
  <   #21 = Utf8               A_1$$anonfun$f$1
  <   #22 = Class              #21            //  A_1$$anonfun$f$1
  <   #23 = Utf8               Code
  ---
  >   #21 = Utf8               Code
  • Loading branch information...
commit 075f6f260ccfba83b118c308195d1ede2e66ad18 1 parent 05681d4
@paulp paulp authored
View
4 src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -86,6 +86,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
if (settings.Xdce.value)
for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) {
log(s"Optimizer eliminated ${sym.fullNameString}")
+ deadCode.elidedClosures += sym
icodes.classes -= sym
}
@@ -624,7 +625,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
innerClassBuffer += m
}
- val allInners: List[Symbol] = innerClassBuffer.toList
+ val allInners: List[Symbol] = innerClassBuffer.toList filterNot deadCode.elidedClosures
+
if (allInners.nonEmpty) {
debuglog(csym.fullName('.') + " contains " + allInners.size + " inner classes.")
View
8 src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
@@ -40,7 +40,13 @@ abstract class DeadCodeElimination extends SubComponent {
}
/** closures that are instantiated at least once, after dead code elimination */
- val liveClosures: mutable.Set[Symbol] = new mutable.HashSet()
+ val liveClosures = perRunCaches.newSet[Symbol]()
+
+ /** closures that are eliminated, populated by GenASM.AsmPhase.run()
+ * these class symbols won't have a .class physical file, thus shouldn't be included in InnerClasses JVM attribute,
+ * otherwise some tools get confused or slow (SI-6546)
+ * */
+ val elidedClosures = perRunCaches.newSet[Symbol]()
/** Remove dead code.
*/
View
1  test/files/run/t6546.flags
@@ -0,0 +1 @@
+-optimise
View
6 test/files/run/t6546/A_1.scala
@@ -0,0 +1,6 @@
+final class Opt {
+ @inline def getOrElse(x: => String): String = ""
+}
+class A_1 {
+ def f(x: Opt): String = x getOrElse null
+}
View
8 test/files/run/t6546/B_2.scala
@@ -0,0 +1,8 @@
+import scala.tools.partest.BytecodeTest
+
+object Test extends BytecodeTest {
+ def show: Unit = {
+ val node = loadClassNode("A_1")
+ assert(node.innerClasses.isEmpty, node.innerClasses)
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.