Skip to content

Commit e948073

Browse files
committed
SI-8582 emit InnerClasses attribute in GenBCode
I removed the `-bcode` test since we have a build that passes `-Ybackend:GenBCode` to all tests. Short intro do the [`InnerClass` attribute][1]: - A class needs one `InnerClass` attribute for each of its nested classes - A class needs the `InnerClass` attribute for all (nested) classes that are mentioned in its constant pool The attribute for a nested class `A$B$C` consists of the long name of the outer class `A$B`, the short name of the inner class `C`, and an access flag set describig the visibility. The attribute seems to be used for reflection. [1]: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.6
1 parent d430b03 commit e948073

File tree

6 files changed

+114
-25
lines changed

6 files changed

+114
-25
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,13 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
116116
addClassFields()
117117

118118
innerClassBufferASM ++= trackMemberClasses(claszSymbol, Nil)
119-
120119
gen(cd.impl)
120+
addInnerClassesASM(cnode, innerClassBufferASM.toList)
121121

122122
if (AsmUtils.traceClassEnabled && cnode.name.contains(AsmUtils.traceClassPattern))
123123
AsmUtils.traceClass(cnode)
124124

125+
cnode.innerClasses
125126
assert(cd.symbol == claszSymbol, "Someone messed up BCodePhase.claszSymbol during genPlainClass().")
126127

127128
} // end of method genPlainClass()

test/files/run/t8582.check

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,44 @@
1-
class p1.p2.Singleton$Singleton$
2-
List(class p1.p2.Singleton$Singleton$Singleton$)
1+
getClass on module gives module class
2+
class p1.p2.Singleton$Singleton$
3+
4+
Nested module classes are found through reflection
5+
p1.p2.Singleton$Singleton$: List(class p1.p2.Singleton$Singleton$Singleton$)
6+
7+
Reflection can find direct nested classes (A1-B1-C1)
8+
A1: List(class A1$B1)
9+
A1$B1: List(class A1$B1$C1)
10+
A1$B1$C1: List()
11+
12+
Reflection can find direct nested classes (A2-B2-C2)
13+
A2: List(class A2$B2)
14+
A2$B2: List(class A2$B2$C2)
15+
A2$B2$C2: List()
16+
17+
Mirror classes have the same InnerClass attributes as the corresponding module class:
18+
className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9]
19+
Module class
20+
className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9]
21+
22+
An outer class has a InnerClass attribute for direct nested classes
23+
className[A1$B1] outerClassName[A1] innerName[B1] access[1]
24+
A nested class has an InnerClass attribute for itself (and also for its nested classes)
25+
className[A1$B1] outerClassName[A1] innerName[B1] access[1]
26+
className[A1$B1$C1] outerClassName[A1$B1] innerName[C1] access[1]
27+
C1 is a nested class, so it has an InnerClass attribute for itself.
28+
Because that attribute leads to an entry for B1 in the constant pool, C1 needs an InnerClass attribute for B1.
29+
className[A1$B1] outerClassName[A1] innerName[B1] access[1]
30+
className[A1$B1$C1] outerClassName[A1$B1] innerName[C1] access[1]
31+
32+
The BeanInfo class has the same InnerClass attributes as the corresponding bean
33+
className[A1$B1] outerClassName[A1] innerName[B1] access[1]
34+
className[A1$B1$C1] outerClassName[A1$B1] innerName[C1] access[1]
35+
36+
Class A2 mentions class C2 in the constant pool (due to method f), therefore it needs an InnerClass attribute for C1
37+
className[A2$B2] outerClassName[A2] innerName[B2] access[1]
38+
className[A2$B2$C2] outerClassName[A2$B2] innerName[C2] access[1]
39+
B2
40+
className[A2$B2] outerClassName[A2] innerName[B2] access[1]
41+
className[A2$B2$C2] outerClassName[A2$B2] innerName[C2] access[1]
42+
C2
43+
className[A2$B2] outerClassName[A2] innerName[B2] access[1]
44+
className[A2$B2$C2] outerClassName[A2$B2] innerName[C2] access[1]

test/files/run/t8582.scala

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import scala.tools.partest.BytecodeTest
2+
import scala.collection.JavaConverters._
3+
14
package p1 {
25
package p2 {
36
object Singleton {
@@ -8,9 +11,71 @@ package p1 {
811
}
912
}
1013

14+
class A1 {
15+
class B1 {
16+
@scala.beans.BeanInfo
17+
class C1
18+
}
19+
}
20+
21+
class A2 {
22+
class B2 {
23+
class C2
24+
}
25+
def f: B2#C2 = null
26+
}
27+
1128

12-
object Test extends App {
29+
object Test extends BytecodeTest {
1330
import p1.p2._
14-
println(Singleton.Singleton.getClass)
15-
println(Singleton.Singleton.getClass.getDeclaredClasses.toList)
31+
32+
def nested(c: Class[_]) = s" ${c.getName}: ${c.getDeclaredClasses.toList}"
33+
34+
def nprintln(s: String) = println("\n"+s)
35+
def printInner(cname: String): Unit = {
36+
val cnode = loadClassNode(cname)
37+
println(cnode.innerClasses.asScala.toList.map(i => s"className[${i.name}] outerClassName[${i.outerName}] innerName[${i.innerName}] access[${i.access}]").mkString(" ", "\n ", ""))
38+
}
39+
40+
def show() {
41+
42+
println("getClass on module gives module class")
43+
println(" " + Singleton.Singleton.getClass)
44+
45+
nprintln("Nested module classes are found through reflection")
46+
println(nested(Singleton.Singleton.getClass))
47+
48+
nprintln("Reflection can find direct nested classes (A1-B1-C1)")
49+
println(nested(classOf[A1]))
50+
println(nested(classOf[A1#B1]))
51+
println(nested(classOf[A1#B1#C1]))
52+
53+
nprintln("Reflection can find direct nested classes (A2-B2-C2)")
54+
println(nested(classOf[A2]))
55+
println(nested(classOf[A2#B2]))
56+
println(nested(classOf[A2#B2#C2]))
57+
58+
nprintln("Mirror classes have the same InnerClass attributes as the corresponding module class:")
59+
printInner("p1.p2.Singleton") // mirror class
60+
println("Module class")
61+
printInner("p1.p2.Singleton$")
62+
63+
nprintln("An outer class has a InnerClass attribute for direct nested classes")
64+
printInner("A1")
65+
println("A nested class has an InnerClass attribute for itself (and also for its nested classes)")
66+
printInner("A1$B1")
67+
println("C1 is a nested class, so it has an InnerClass attribute for itself.\n"+
68+
"Because that attribute leads to an entry for B1 in the constant pool, C1 needs an InnerClass attribute for B1.")
69+
printInner("A1$B1$C1")
70+
71+
nprintln("The BeanInfo class has the same InnerClass attributes as the corresponding bean")
72+
printInner("A1$B1$C1BeanInfo")
73+
74+
nprintln("Class A2 mentions class C2 in the constant pool (due to method f), therefore it needs an InnerClass attribute for C1")
75+
printInner("A2")
76+
println("B2")
77+
printInner("A2$B2")
78+
println("C2")
79+
printInner("A2$B2$C2")
80+
}
1681
}

test/pending/run/t8582-bcode.check

Lines changed: 0 additions & 2 deletions
This file was deleted.

test/pending/run/t8582-bcode.flags

Lines changed: 0 additions & 1 deletion
This file was deleted.

test/pending/run/t8582-bcode.scala

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)