@@ -8,6 +8,9 @@ package backend.jvm
88
99import scala .tools .asm
1010import asm .Opcodes
11+ import scala .tools .asm .tree .{InnerClassNode , ClassNode }
12+ import opt .CodeRepository
13+ import scala .collection .convert .decorateAsScala ._
1114
1215/**
1316 * The BTypes component defines The BType class hierarchy. BTypes encapsulate all type information
@@ -20,6 +23,17 @@ import asm.Opcodes
2023abstract class BTypes {
2124 import BTypes .InternalName
2225
26+ // Some core BTypes are required here, in class BType, where no Global instance is available.
27+ // The Global is only available in the subclass BTypesFromSymbols. We cannot depend on the actual
28+ // implementation (CoreBTypesProxy) here because it has members that refer to global.Symbol.
29+ val coreBTypes : CoreBTypesProxyGlobalIndependent [this .type ]
30+ import coreBTypes ._
31+
32+ /**
33+ * Tools for parsing classfiles, used by the inliner.
34+ */
35+ val codeRepository : CodeRepository
36+
2337 /**
2438 * A map from internal names to ClassBTypes. Every ClassBType is added to this map on its
2539 * construction.
@@ -31,18 +45,77 @@ abstract class BTypes {
3145 * Concurrent because stack map frames are computed when in the class writer, which might run
3246 * on multiple classes concurrently.
3347 */
34- protected val classBTypeFromInternalNameMap : collection.concurrent.Map [InternalName , ClassBType ]
48+ val classBTypeFromInternalName : collection.concurrent.Map [InternalName , ClassBType ]
3549
3650 /**
37- * Obtain a previously constructed ClassBType for a given internal name .
51+ * Parse the classfile for `internalName` and construct the [[ ClassBType ]] .
3852 */
39- def classBTypeFromInternalName (internalName : InternalName ) = classBTypeFromInternalNameMap(internalName)
53+ def classBTypeFromParsedClassfile (internalName : InternalName ): ClassBType = {
54+ classBTypeFromClassNode(codeRepository.classNode(internalName))
55+ }
4056
41- // Some core BTypes are required here, in class BType, where no Global instance is available.
42- // The Global is only available in the subclass BTypesFromSymbols. We cannot depend on the actual
43- // implementation (CoreBTypesProxy) here because it has members that refer to global.Symbol.
44- val coreBTypes : CoreBTypesProxyGlobalIndependent [this .type ]
45- import coreBTypes ._
57+ /**
58+ * Construct the [[ClassBType ]] for a parsed classfile.
59+ */
60+ def classBTypeFromClassNode (classNode : ClassNode ): ClassBType = {
61+ classBTypeFromInternalName.getOrElse(classNode.name, {
62+ setClassInfo(classNode, ClassBType (classNode.name))
63+ })
64+ }
65+
66+ private def setClassInfo (classNode : ClassNode , classBType : ClassBType ): ClassBType = {
67+ val superClass = classNode.superName match {
68+ case null =>
69+ assert(classNode.name == ObjectReference .internalName, s " class with missing super type: ${classNode.name}" )
70+ None
71+ case superName =>
72+ Some (classBTypeFromParsedClassfile(superName))
73+ }
74+
75+ val interfaces : List [ClassBType ] = classNode.interfaces.asScala.map(classBTypeFromParsedClassfile)(collection.breakOut)
76+
77+ val flags = classNode.access
78+
79+ /**
80+ * Find all nested classes of classNode. The innerClasses attribute contains all nested classes
81+ * that are declared inside classNode or used in the bytecode of classNode. So some of them are
82+ * nested in some other class than classNode, and we need to filter them.
83+ *
84+ * For member classes, innerClassNode.outerName is defined, so we compare that to classNode.name.
85+ *
86+ * For local and anonymous classes, innerClassNode.outerName is null. Such classes are required
87+ * to have an EnclosingMethod attribute declaring the outer class. So we keep those local and
88+ * anonymous classes whose outerClass is classNode.name.
89+ *
90+ */
91+ def nestedInCurrentClass (innerClassNode : InnerClassNode ): Boolean = {
92+ (innerClassNode.outerName != null && innerClassNode.outerName == classNode.name) ||
93+ (innerClassNode.outerName == null && codeRepository.classNode(innerClassNode.name).outerClass == classNode.name)
94+ }
95+
96+ val nestedClasses : List [ClassBType ] = classNode.innerClasses.asScala.collect({
97+ case i if nestedInCurrentClass(i) => classBTypeFromParsedClassfile(i.name)
98+ })(collection.breakOut)
99+
100+ // if classNode is a nested class, it has an innerClass attribute for itself. in this
101+ // case we build the NestedInfo.
102+ val nestedInfo = classNode.innerClasses.asScala.find(_.name == classNode.name) map {
103+ case innerEntry =>
104+ val enclosingClass =
105+ if (innerEntry.outerName != null ) {
106+ // if classNode is a member class, the outerName is non-null
107+ classBTypeFromParsedClassfile(innerEntry.outerName)
108+ } else {
109+ // for anonymous or local classes, the outerName is null, but the enclosing class is
110+ // stored in the EnclosingMethod attribute (which ASM encodes in classNode.outerClass).
111+ classBTypeFromParsedClassfile(classNode.outerClass)
112+ }
113+ val staticFlag = (innerEntry.access & Opcodes .ACC_STATIC ) != 0
114+ NestedInfo (enclosingClass, Option (innerEntry.outerName), Option (innerEntry.innerName), staticFlag)
115+ }
116+ classBType.info = ClassInfo (superClass, interfaces, flags, nestedClasses, nestedInfo)
117+ classBType
118+ }
46119
47120 /**
48121 * A BType is either a primitive type, a ClassBType, an ArrayBType of one of these, or a MethodType
@@ -574,7 +647,7 @@ abstract class BTypes {
574647 * nested classes. Example: for the definition `class A { class B }` we have
575648 *
576649 * B.info.nestedInfo.outerClass == A
577- * A.info.memberClasses contains B
650+ * A.info.nestedClasses contains B
578651 */
579652 private var _info : ClassInfo = null
580653
@@ -589,15 +662,15 @@ abstract class BTypes {
589662 checkInfoConsistency()
590663 }
591664
592- classBTypeFromInternalNameMap (internalName) = this
665+ classBTypeFromInternalName (internalName) = this
593666
594667 private def checkInfoConsistency (): Unit = {
595668 // we assert some properties. however, some of the linked ClassBType (members, superClass,
596669 // interfaces) may not yet have an `_info` (initialization of cyclic structures). so we do a
597670 // best-effort verification.
598671 def ifInit (c : ClassBType )(p : ClassBType => Boolean ): Boolean = c._info == null || p(c)
599672
600- def isJLO (t : ClassBType ) = t.internalName == " java/lang/Object "
673+ def isJLO (t : ClassBType ) = t.internalName == ObjectReference .internalName
601674
602675 assert(! ClassBType .isInternalPhantomType(internalName), s " Cannot create ClassBType for phantom type $this" )
603676
@@ -612,7 +685,7 @@ abstract class BTypes {
612685 s " Invalid interfaces in $this: ${info.interfaces}"
613686 )
614687
615- assert(info.memberClasses .forall(c => ifInit(c)(_.isNestedClass)), info.memberClasses )
688+ assert(info.nestedClasses .forall(c => ifInit(c)(_.isNestedClass)), info.nestedClasses )
616689 }
617690
618691 /**
@@ -640,8 +713,9 @@ abstract class BTypes {
640713 outerName.orNull,
641714 innerName.orNull,
642715 GenBCode .mkFlags(
643- info.flags,
644- if (isStaticNestedClass) asm.Opcodes .ACC_STATIC else 0
716+ // the static flag in the InnerClass table has a special meaning, see InnerClass comment
717+ info.flags & ~ Opcodes .ACC_STATIC ,
718+ if (isStaticNestedClass) Opcodes .ACC_STATIC else 0
645719 ) & ClassBType .INNER_CLASSES_FLAGS
646720 )
647721 }
@@ -757,12 +831,12 @@ abstract class BTypes {
757831 * through the superclass.
758832 * @param flags The java flags, obtained through `javaFlags`. Used also to derive
759833 * the flags for InnerClass entries.
760- * @param memberClasses Classes nested in this class. Those need to be added to the
834+ * @param nestedClasses Classes nested in this class. Those need to be added to the
761835 * InnerClass table, see the InnerClass spec summary above.
762836 * @param nestedInfo If this describes a nested class, information for the InnerClass table.
763837 */
764- case class ClassInfo (superClass : Option [ClassBType ], interfaces : List [ClassBType ], flags : Int ,
765- memberClasses : List [ClassBType ], nestedInfo : Option [NestedInfo ])
838+ final case class ClassInfo (superClass : Option [ClassBType ], interfaces : List [ClassBType ], flags : Int ,
839+ nestedClasses : List [ClassBType ], nestedInfo : Option [NestedInfo ])
766840
767841 /**
768842 * Information required to add a class to an InnerClass table.
@@ -779,10 +853,10 @@ abstract class BTypes {
779853 * a source-level property: if the class is in a static context (does not have an outer pointer).
780854 * This is checked when building the NestedInfo.
781855 */
782- case class NestedInfo (enclosingClass : ClassBType ,
783- outerName : Option [String ],
784- innerName : Option [String ],
785- isStaticNestedClass : Boolean )
856+ final case class NestedInfo (enclosingClass : ClassBType ,
857+ outerName : Option [String ],
858+ innerName : Option [String ],
859+ isStaticNestedClass : Boolean )
786860
787861 /**
788862 * This class holds the data for an entry in the InnerClass table. See the InnerClass summary
0 commit comments