-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3745 from lrytz/t8582
SI-8582 emit InnerClasses attribute in GenBCode
- Loading branch information
Showing
16 changed files
with
235 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* NSC -- new Scala compiler | ||
* Copyright 2005-2014 LAMP/EPFL | ||
* @author Martin Odersky | ||
*/ | ||
|
||
package scala.tools.nsc.backend.jvm | ||
|
||
import scala.tools.asm.tree.{ClassNode, MethodNode} | ||
import java.io.PrintWriter | ||
import scala.tools.asm.util.{TraceClassVisitor, TraceMethodVisitor, Textifier} | ||
|
||
object AsmUtils { | ||
|
||
/** | ||
* Print the bytecode of methods generated by GenBCode to the standard output. Only methods | ||
* whose name contains `traceMethodPattern` are traced. | ||
*/ | ||
final val traceMethodEnabled = false | ||
final val traceMethodPattern = "" | ||
|
||
/** | ||
* Print the bytecode of classes generated by GenBCode to the standard output. | ||
*/ | ||
final val traceClassEnabled = false | ||
final val traceClassPattern = "" | ||
|
||
/** | ||
* Print the bytedcode of classes as they are serialized by the ASM library. The serialization | ||
* performed by `asm.ClassWriter` can change the code generated by GenBCode. For example, it | ||
* introduces stack map frames, it computes the maximal stack sizes, and it replaces dead | ||
* code by NOPs (see also https://github.com/scala/scala/pull/3726#issuecomment-42861780). | ||
*/ | ||
final val traceSerializedClassEnabled = false | ||
final val traceSerializedClassPattern = "" | ||
|
||
def traceMethod(mnode: MethodNode): Unit = { | ||
println(s"Bytecode for method ${mnode.name}") | ||
val p = new Textifier | ||
val tracer = new TraceMethodVisitor(p) | ||
mnode.accept(tracer) | ||
val w = new PrintWriter(System.out) | ||
p.print(w) | ||
w.flush() | ||
} | ||
|
||
def traceClass(cnode: ClassNode): Unit = { | ||
println(s"Bytecode for class ${cnode.name}") | ||
val w = new PrintWriter(System.out) | ||
cnode.accept(new TraceClassVisitor(w)) | ||
w.flush() | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
property descriptors | ||
x -- int -- public int p.C.x() -- null | ||
y -- class java.lang.String -- public java.lang.String p.C.y() -- public void p.C.y_$eq(java.lang.String) | ||
z -- class scala.collection.immutable.List -- public scala.collection.immutable.List p.C.z() -- public void p.C.z_$eq(scala.collection.immutable.List) | ||
method descriptors | ||
f -- public p.C p.C.f() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package p | ||
|
||
@scala.beans.BeanInfo | ||
class C { | ||
val x: Int = 0 | ||
var y: String = "" | ||
var z: List[_] = Nil | ||
def f: C = ??? | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
object Test extends App { | ||
val info = java.beans.Introspector.getBeanInfo(classOf[p.C]) | ||
|
||
println("property descriptors") | ||
|
||
val pds = info.getPropertyDescriptors | ||
for (pd <- pds) { | ||
println(s"${pd.getName} -- ${pd.getPropertyType} -- ${pd.getReadMethod} -- ${pd.getWriteMethod}") | ||
} | ||
|
||
println("method descriptors") | ||
|
||
val mds = info.getMethodDescriptors | ||
for (md <- mds) { | ||
println(s"${md.getName} -- ${md.getMethod}") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
getClass on module gives module class | ||
class p1.p2.Singleton$Singleton$ | ||
|
||
Nested module classes are found through reflection | ||
p1.p2.Singleton$Singleton$: List(class p1.p2.Singleton$Singleton$Singleton$) | ||
|
||
Reflection can find direct nested classes (A1-B1-C1) | ||
A1: List(class A1$B1) | ||
A1$B1: List(class A1$B1$C1) | ||
A1$B1$C1: List() | ||
|
||
Reflection can find direct nested classes (A2-B2-C2) | ||
A2: List(class A2$B2) | ||
A2$B2: List(class A2$B2$C2) | ||
A2$B2$C2: List() | ||
|
||
Mirror classes have the same InnerClass attributes as the corresponding module class: | ||
className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9] | ||
Module class | ||
className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9] | ||
|
||
An outer class has a InnerClass attribute for direct nested classes | ||
className[A1$B1] outerClassName[A1] innerName[B1] access[1] | ||
A nested class has an InnerClass attribute for itself (and also for its nested classes) | ||
className[A1$B1] outerClassName[A1] innerName[B1] access[1] | ||
className[A1$B1$C1] outerClassName[A1$B1] innerName[C1] access[1] | ||
C1 is a nested class, so it has an InnerClass attribute for itself. | ||
Because that attribute leads to an entry for B1 in the constant pool, C1 needs an InnerClass attribute for B1. | ||
className[A1$B1] outerClassName[A1] innerName[B1] access[1] | ||
className[A1$B1$C1] outerClassName[A1$B1] innerName[C1] access[1] | ||
|
||
The BeanInfo class has the same InnerClass attributes as the corresponding bean | ||
className[A1$B1] outerClassName[A1] innerName[B1] access[1] | ||
className[A1$B1$C1] outerClassName[A1$B1] innerName[C1] access[1] | ||
|
||
Class A2 mentions class C2 in the constant pool (due to method f), therefore it needs an InnerClass attribute for C1 | ||
className[A2$B2] outerClassName[A2] innerName[B2] access[1] | ||
className[A2$B2$C2] outerClassName[A2$B2] innerName[C2] access[1] | ||
B2 | ||
className[A2$B2] outerClassName[A2] innerName[B2] access[1] | ||
className[A2$B2$C2] outerClassName[A2$B2] innerName[C2] access[1] | ||
C2 | ||
className[A2$B2] outerClassName[A2] innerName[B2] access[1] | ||
className[A2$B2$C2] outerClassName[A2$B2] innerName[C2] access[1] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import scala.tools.partest.BytecodeTest | ||
import scala.collection.JavaConverters._ | ||
|
||
package p1 { | ||
package p2 { | ||
object Singleton { | ||
object Singleton { | ||
object Singleton | ||
} | ||
} | ||
} | ||
} | ||
|
||
class A1 { | ||
class B1 { | ||
@scala.beans.BeanInfo | ||
class C1 | ||
} | ||
} | ||
|
||
class A2 { | ||
class B2 { | ||
class C2 | ||
} | ||
def f: B2#C2 = null | ||
} | ||
|
||
|
||
object Test extends BytecodeTest { | ||
import p1.p2._ | ||
|
||
def nested(c: Class[_]) = s" ${c.getName}: ${c.getDeclaredClasses.toList}" | ||
|
||
def nprintln(s: String) = println("\n"+s) | ||
def printInner(cname: String): Unit = { | ||
val cnode = loadClassNode(cname) | ||
println(cnode.innerClasses.asScala.toList.map(i => s"className[${i.name}] outerClassName[${i.outerName}] innerName[${i.innerName}] access[${i.access}]").mkString(" ", "\n ", "")) | ||
} | ||
|
||
def show() { | ||
|
||
println("getClass on module gives module class") | ||
println(" " + Singleton.Singleton.getClass) | ||
|
||
nprintln("Nested module classes are found through reflection") | ||
println(nested(Singleton.Singleton.getClass)) | ||
|
||
nprintln("Reflection can find direct nested classes (A1-B1-C1)") | ||
println(nested(classOf[A1])) | ||
println(nested(classOf[A1#B1])) | ||
println(nested(classOf[A1#B1#C1])) | ||
|
||
nprintln("Reflection can find direct nested classes (A2-B2-C2)") | ||
println(nested(classOf[A2])) | ||
println(nested(classOf[A2#B2])) | ||
println(nested(classOf[A2#B2#C2])) | ||
|
||
nprintln("Mirror classes have the same InnerClass attributes as the corresponding module class:") | ||
printInner("p1.p2.Singleton") // mirror class | ||
println("Module class") | ||
printInner("p1.p2.Singleton$") | ||
|
||
nprintln("An outer class has a InnerClass attribute for direct nested classes") | ||
printInner("A1") | ||
println("A nested class has an InnerClass attribute for itself (and also for its nested classes)") | ||
printInner("A1$B1") | ||
println("C1 is a nested class, so it has an InnerClass attribute for itself.\n"+ | ||
"Because that attribute leads to an entry for B1 in the constant pool, C1 needs an InnerClass attribute for B1.") | ||
printInner("A1$B1$C1") | ||
|
||
nprintln("The BeanInfo class has the same InnerClass attributes as the corresponding bean") | ||
printInner("A1$B1$C1BeanInfo") | ||
|
||
nprintln("Class A2 mentions class C2 in the constant pool (due to method f), therefore it needs an InnerClass attribute for C1") | ||
printInner("A2") | ||
println("B2") | ||
printInner("A2$B2") | ||
println("C2") | ||
printInner("A2$B2$C2") | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.