Skip to content

Commit 72352dc

Browse files
authored
Merge pull request #15153 from WojciechMazur/backport/scala-pr-4807
Simplify and correctify calculation of the InnerClass attribute
2 parents 11e4b30 + 0aa184d commit 72352dc

10 files changed

+557
-235
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 27 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
3939
import DottyBackendInterface.symExtensions
4040
import bTypes._
4141
import coreBTypes._
42-
import BCodeBodyBuilder._
4342

4443
protected val primitives: DottyPrimitives
4544

@@ -431,7 +430,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
431430
if (value.tag != UnitTag) (value.tag, expectedType) match {
432431
case (IntTag, LONG ) => bc.lconst(value.longValue); generatedType = LONG
433432
case (FloatTag, DOUBLE) => bc.dconst(value.doubleValue); generatedType = DOUBLE
434-
case (NullTag, _ ) => bc.emit(asm.Opcodes.ACONST_NULL); generatedType = RT_NULL
433+
case (NullTag, _ ) => bc.emit(asm.Opcodes.ACONST_NULL); generatedType = srNullRef
435434
case _ => genConstant(value); generatedType = tpeTK(tree)
436435
}
437436

@@ -490,7 +489,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
490489
val thrownType = expectedType
491490
// `throw null` is valid although scala.Null (as defined in src/libray-aux) isn't a subtype of Throwable.
492491
// Similarly for scala.Nothing (again, as defined in src/libray-aux).
493-
assert(thrownType.isNullType || thrownType.isNothingType || thrownType.asClassBType.isSubtypeOf(ThrowableReference))
492+
assert(thrownType.isNullType || thrownType.isNothingType || thrownType.asClassBType.isSubtypeOf(jlThrowableRef))
494493
emit(asm.Opcodes.ATHROW)
495494
end genAdaptAndSendToDest
496495

@@ -674,8 +673,8 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
674673
else if (l.isPrimitive) {
675674
bc drop l
676675
if (cast) {
677-
mnode.visitTypeInsn(asm.Opcodes.NEW, classCastExceptionReference.internalName)
678-
bc dup ObjectReference
676+
mnode.visitTypeInsn(asm.Opcodes.NEW, jlClassCastExceptionRef.internalName)
677+
bc dup ObjectRef
679678
emit(asm.Opcodes.ATHROW)
680679
} else {
681680
bc boolconst false
@@ -777,15 +776,15 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
777776
val nativeKind = tpeTK(expr)
778777
genLoad(expr, nativeKind)
779778
val MethodNameAndType(mname, methodType) = asmBoxTo(nativeKind)
780-
bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor, itf = false)
779+
bc.invokestatic(srBoxesRuntimeRef.internalName, mname, methodType.descriptor, itf = false)
781780
generatedType = boxResultType(fun.symbol) // was toTypeKind(fun.symbol.tpe.resultType)
782781

783782
case Apply(fun, List(expr)) if Erasure.Boxing.isUnbox(fun.symbol) && fun.symbol.denot.owner != defn.UnitModuleClass =>
784783
genLoad(expr)
785784
val boxType = unboxResultType(fun.symbol) // was toTypeKind(fun.symbol.owner.linkedClassOfClass.tpe)
786785
generatedType = boxType
787786
val MethodNameAndType(mname, methodType) = asmUnboxTo(boxType)
788-
bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor, itf = false)
787+
bc.invokestatic(srBoxesRuntimeRef.internalName, mname, methodType.descriptor, itf = false)
789788

790789
case app @ Apply(fun, args) =>
791790
val sym = fun.symbol
@@ -1237,7 +1236,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
12371236
liftStringConcat(tree) match {
12381237
// Optimization for expressions of the form "" + x
12391238
case List(Literal(Constant("")), arg) =>
1240-
genLoad(arg, ObjectReference)
1239+
genLoad(arg, ObjectRef)
12411240
genCallMethod(defn.String_valueOf_Object, InvokeStyle.Static)
12421241

12431242
case concatenations =>
@@ -1409,7 +1408,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
14091408

14101409
/* Generate the scala ## method. */
14111410
def genScalaHash(tree: Tree): BType = {
1412-
genLoad(tree, ObjectReference)
1411+
genLoad(tree, ObjectRef)
14131412
genCallMethod(NoSymbol, InvokeStyle.Static) // used to dispatch ## on primitives to ScalaRuntime.hash. Should be implemented by a miniphase
14141413
}
14151414

@@ -1508,8 +1507,8 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
15081507
val nonNullSide = if (ScalaPrimitivesOps.isReferenceEqualityOp(code)) ifOneIsNull(l, r) else null
15091508
if (nonNullSide != null) {
15101509
// special-case reference (in)equality test for null (null eq x, x eq null)
1511-
genLoad(nonNullSide, ObjectReference)
1512-
genCZJUMP(success, failure, op, ObjectReference, targetIfNoJump)
1510+
genLoad(nonNullSide, ObjectRef)
1511+
genCZJUMP(success, failure, op, ObjectRef, targetIfNoJump)
15131512
} else {
15141513
val tk = tpeTK(l).maxType(tpeTK(r))
15151514
genLoad(l, tk)
@@ -1627,42 +1626,42 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
16271626
} else defn.BoxesRunTimeModule_externalEquals
16281627
}
16291628

1630-
genLoad(l, ObjectReference)
1631-
genLoad(r, ObjectReference)
1629+
genLoad(l, ObjectRef)
1630+
genLoad(r, ObjectRef)
16321631
genCallMethod(equalsMethod, InvokeStyle.Static)
16331632
genCZJUMP(success, failure, Primitives.NE, BOOL, targetIfNoJump)
16341633
}
16351634
else {
16361635
if (isNull(l)) {
16371636
// null == expr -> expr eq null
1638-
genLoad(r, ObjectReference)
1639-
genCZJUMP(success, failure, Primitives.EQ, ObjectReference, targetIfNoJump)
1637+
genLoad(r, ObjectRef)
1638+
genCZJUMP(success, failure, Primitives.EQ, ObjectRef, targetIfNoJump)
16401639
} else if (isNull(r)) {
16411640
// expr == null -> expr eq null
1642-
genLoad(l, ObjectReference)
1643-
genCZJUMP(success, failure, Primitives.EQ, ObjectReference, targetIfNoJump)
1641+
genLoad(l, ObjectRef)
1642+
genCZJUMP(success, failure, Primitives.EQ, ObjectRef, targetIfNoJump)
16441643
} else if (isNonNullExpr(l)) {
16451644
// SI-7852 Avoid null check if L is statically non-null.
1646-
genLoad(l, ObjectReference)
1647-
genLoad(r, ObjectReference)
1645+
genLoad(l, ObjectRef)
1646+
genLoad(r, ObjectRef)
16481647
genCallMethod(defn.Any_equals, InvokeStyle.Virtual)
16491648
genCZJUMP(success, failure, Primitives.NE, BOOL, targetIfNoJump)
16501649
} else {
16511650
// l == r -> if (l eq null) r eq null else l.equals(r)
1652-
val eqEqTempLocal = locals.makeLocal(ObjectReference, nme.EQEQ_LOCAL_VAR.mangledString, defn.ObjectType, r.span)
1651+
val eqEqTempLocal = locals.makeLocal(ObjectRef, nme.EQEQ_LOCAL_VAR.mangledString, defn.ObjectType, r.span)
16531652
val lNull = new asm.Label
16541653
val lNonNull = new asm.Label
16551654

1656-
genLoad(l, ObjectReference)
1657-
genLoad(r, ObjectReference)
1655+
genLoad(l, ObjectRef)
1656+
genLoad(r, ObjectRef)
16581657
locals.store(eqEqTempLocal)
1659-
bc dup ObjectReference
1660-
genCZJUMP(lNull, lNonNull, Primitives.EQ, ObjectReference, targetIfNoJump = lNull)
1658+
bc dup ObjectRef
1659+
genCZJUMP(lNull, lNonNull, Primitives.EQ, ObjectRef, targetIfNoJump = lNull)
16611660

16621661
markProgramPoint(lNull)
1663-
bc drop ObjectReference
1662+
bc drop ObjectRef
16641663
locals.load(eqEqTempLocal)
1665-
genCZJUMP(success, failure, Primitives.EQ, ObjectReference, targetIfNoJump = lNonNull)
1664+
genCZJUMP(success, failure, Primitives.EQ, ObjectRef, targetIfNoJump = lNonNull)
16661665

16671666
markProgramPoint(lNonNull)
16681667
locals.load(eqEqTempLocal)
@@ -1753,9 +1752,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
17531752

17541753
val metafactory =
17551754
if (flags != 0)
1756-
lambdaMetaFactoryAltMetafactoryHandle // altMetafactory required to be able to pass the flags and additional arguments if needed
1755+
jliLambdaMetaFactoryAltMetafactoryHandle // altMetafactory required to be able to pass the flags and additional arguments if needed
17571756
else
1758-
lambdaMetaFactoryMetafactoryHandle
1757+
jliLambdaMetaFactoryMetafactoryHandle
17591758

17601759
bc.jmethod.visitInvokeDynamicInsn(methodName, desc, metafactory, bsmArgs: _*)
17611760

@@ -1772,27 +1771,5 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
17721771
private def isEmittedInterface(sym: Symbol): Boolean = sym.isInterface ||
17731772
sym.is(JavaDefined) && (toDenot(sym).isAnnotation || sym.is(ModuleClass) && (sym.companionClass.is(PureInterface)) || sym.companionClass.is(Trait))
17741773

1775-
}
17761774

1777-
object BCodeBodyBuilder {
1778-
val lambdaMetaFactoryMetafactoryHandle = new Handle(
1779-
Opcodes.H_INVOKESTATIC,
1780-
"java/lang/invoke/LambdaMetafactory",
1781-
"metafactory",
1782-
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;",
1783-
/* itf = */ false)
1784-
1785-
val lambdaMetaFactoryAltMetafactoryHandle = new Handle(
1786-
Opcodes.H_INVOKESTATIC,
1787-
"java/lang/invoke/LambdaMetafactory",
1788-
"altMetafactory",
1789-
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;",
1790-
/* itf = */ false)
1791-
1792-
val lambdaDeserializeBootstrapHandle = new Handle(
1793-
Opcodes.H_INVOKESTATIC,
1794-
"scala/runtime/LambdaDeserialize",
1795-
"bootstrap",
1796-
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;",
1797-
/* itf = */ false)
17981775
}

compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala

Lines changed: 32 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -132,24 +132,24 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
132132
}
133133

134134
/*
135-
* Populates the InnerClasses JVM attribute with `refedInnerClasses`.
136-
* In addition to inner classes mentioned somewhere in `jclass` (where `jclass` is a class file being emitted)
137-
* `refedInnerClasses` should contain those inner classes defined as direct member classes of `jclass`
138-
* but otherwise not mentioned in `jclass`.
135+
* Populates the InnerClasses JVM attribute with `refedInnerClasses`. See also the doc on inner
136+
* classes in BTypes.scala.
139137
*
140-
* `refedInnerClasses` may contain duplicates,
141-
* need not contain the enclosing inner classes of each inner class it lists (those are looked up for consistency).
138+
* `refedInnerClasses` may contain duplicates, need not contain the enclosing inner classes of
139+
* each inner class it lists (those are looked up and included).
142140
*
143-
* This method serializes in the InnerClasses JVM attribute in an appropriate order,
141+
* This method serializes in the InnerClasses JVM attribute in an appropriate order,
144142
* not necessarily that given by `refedInnerClasses`.
145143
*
146144
* can-multi-thread
147145
*/
148-
final def addInnerClassesASM(jclass: asm.ClassVisitor, refedInnerClasses: List[ClassBType]): Unit = {
149-
val allNestedClasses = refedInnerClasses.flatMap(_.enclosingNestedClassesChain).distinct
150-
146+
final def addInnerClasses(jclass: asm.ClassVisitor, declaredInnerClasses: List[ClassBType], refedInnerClasses: List[ClassBType]): Unit = {
151147
// sorting ensures nested classes are listed after their enclosing class thus satisfying the Eclipse Java compiler
152-
for (nestedClass <- allNestedClasses.sortBy(_.internalName.toString)) {
148+
val allNestedClasses = new mutable.TreeSet[ClassBType]()(Ordering.by(_.internalName))
149+
allNestedClasses ++= declaredInnerClasses
150+
refedInnerClasses.foreach(allNestedClasses ++= _.enclosingNestedClassesChain)
151+
for nestedClass <- allNestedClasses
152+
do {
153153
// Extract the innerClassEntry - we know it exists, enclosingNestedClassesChain only returns nested classes.
154154
val Some(e) = nestedClass.innerClassAttributeEntry: @unchecked
155155
jclass.visitInnerClass(e.name, e.outerName, e.innerName, e.flags)
@@ -218,26 +218,16 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
218218
final val emitLines = debugLevel >= 2
219219
final val emitVars = debugLevel >= 3
220220

221-
/*
222-
* Contains class-symbols that:
223-
* (a) are known to denote inner classes
224-
* (b) are mentioned somewhere in the class being generated.
225-
*
226-
* In other words, the lifetime of `innerClassBufferASM` is associated to "the class being generated".
227-
*/
228-
final val innerClassBufferASM = mutable.Set.empty[ClassBType]
229-
230221
/**
231-
* The class internal name for a given class symbol. If the symbol describes a nested class, the
232-
* ClassBType is added to the innerClassBufferASM.
222+
* The class internal name for a given class symbol.
233223
*/
234224
final def internalName(sym: Symbol): String = {
235225
// For each java class, the scala compiler creates a class and a module (thus a module class).
236-
// If the `sym` is a java module class, we use the java class instead. This ensures that we
237-
// register the class (instead of the module class) in innerClassBufferASM.
226+
// If the `sym` is a java module class, we use the java class instead. This ensures that the
227+
// ClassBType is created from the main class (instead of the module class).
238228
// The two symbols have the same name, so the resulting internalName is the same.
239229
val classSym = if (sym.is(JavaDefined) && sym.is(ModuleClass)) sym.linkedClass else sym
240-
getClassBTypeAndRegisterInnerClass(classSym).internalName
230+
getClassBType(classSym).internalName
241231
}
242232

243233
private def assertClassNotArray(sym: Symbol): Unit = {
@@ -251,8 +241,7 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
251241
}
252242

253243
/**
254-
* The ClassBType for a class symbol. If the class is nested, the ClassBType is added to the
255-
* innerClassBufferASM.
244+
* The ClassBType for a class symbol.
256245
*
257246
* The class symbol scala.Nothing is mapped to the class scala.runtime.Nothing$. Similarly,
258247
* scala.Null is mapped to scala.runtime.Null$. This is because there exist no class files
@@ -264,16 +253,12 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
264253
* the class descriptor of the receiver (the implementation class) is obtained by creating the
265254
* ClassBType.
266255
*/
267-
final def getClassBTypeAndRegisterInnerClass(sym: Symbol): ClassBType = {
256+
final def getClassBType(sym: Symbol): ClassBType = {
268257
assertClassNotArrayNotPrimitive(sym)
269258

270-
if (sym == defn.NothingClass) RT_NOTHING
271-
else if (sym == defn.NullClass) RT_NULL
272-
else {
273-
val r = classBTypeFromSymbol(sym)
274-
if (r.isNestedClass) innerClassBufferASM += r
275-
r
276-
}
259+
if (sym == defn.NothingClass) srNothingRef
260+
else if (sym == defn.NullClass) srNullRef
261+
else classBTypeFromSymbol(sym)
277262
}
278263

279264
/*
@@ -288,16 +273,14 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
288273
}
289274

290275
/**
291-
* The jvm descriptor of a type. If `t` references a nested class, its ClassBType is added to
292-
* the innerClassBufferASM.
276+
* The jvm descriptor of a type.
293277
*/
294278
final def typeDescriptor(t: Type): String = { toTypeKind(t).descriptor }
295279

296280
/**
297-
* The jvm descriptor for a symbol. If `sym` represents a nested class, its ClassBType is added
298-
* to the innerClassBufferASM.
281+
* The jvm descriptor for a symbol.
299282
*/
300-
final def symDescriptor(sym: Symbol): String = { getClassBTypeAndRegisterInnerClass(sym).descriptor }
283+
final def symDescriptor(sym: Symbol): String = getClassBType(sym).descriptor
301284

302285
final def toTypeKind(tp: Type): BType = typeToTypeKind(tp)(BCodeHelpers.this)(this)
303286

@@ -691,19 +674,18 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
691674
def genMirrorClass(moduleClass: Symbol, cunit: CompilationUnit): asm.tree.ClassNode = {
692675
assert(moduleClass.is(ModuleClass))
693676
assert(moduleClass.companionClass == NoSymbol, moduleClass)
694-
innerClassBufferASM.clear()
695677
this.cunit = cunit
678+
val bType = mirrorClassBTypeFromSymbol(moduleClass)
696679
val moduleName = internalName(moduleClass) // + "$"
697-
val mirrorName = moduleName.substring(0, moduleName.length() - 1)
680+
val mirrorName = bType.internalName
698681

699-
val flags = (asm.Opcodes.ACC_SUPER | asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_FINAL)
700682
val mirrorClass = new asm.tree.ClassNode
701683
mirrorClass.visit(
702684
classfileVersion,
703-
flags,
685+
bType.info.flags,
704686
mirrorName,
705687
null /* no java-generic-signature */,
706-
ObjectReference.internalName,
688+
ObjectRef.internalName,
707689
EMPTY_STRING_ARRAY
708690
)
709691

@@ -717,10 +699,6 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
717699
emitAnnotations(mirrorClass, moduleClass.annotations ++ ssa)
718700

719701
addForwarders(mirrorClass, mirrorName, moduleClass)
720-
721-
innerClassBufferASM ++= classBTypeFromSymbol(moduleClass).info.memberClasses
722-
addInnerClassesASM(mirrorClass, innerClassBufferASM.toList)
723-
724702
mirrorClass.visitEnd()
725703

726704
moduleClass.name // this side-effect is necessary, really.
@@ -754,8 +732,7 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
754732
* must-single-thread
755733
*/
756734
def legacyAddCreatorCode(clinit: asm.MethodVisitor, cnode: asm.tree.ClassNode, thisName: String): Unit = {
757-
// this tracks the inner class in innerClassBufferASM, if needed.
758-
val androidCreatorType = getClassBTypeAndRegisterInnerClass(AndroidCreatorClass)
735+
val androidCreatorType = getClassBType(AndroidCreatorClass)
759736
val tdesc_creator = androidCreatorType.descriptor
760737

761738
cnode.visitField(
@@ -818,8 +795,7 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
818795
def primitiveOrClassToBType(sym: Symbol): BType = {
819796
assert(sym.isClass, sym)
820797
assert(sym != defn.ArrayClass || compilingArray, sym)
821-
primitiveTypeMap.getOrElse(sym,
822-
storage.getClassBTypeAndRegisterInnerClass(sym)).asInstanceOf[BType]
798+
primitiveTypeMap.getOrElse(sym, storage.getClassBType(sym)).asInstanceOf[BType]
823799
}
824800

825801
/**
@@ -828,7 +804,7 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
828804
*/
829805
def nonClassTypeRefToBType(sym: Symbol): ClassBType = {
830806
assert(sym.isType && compilingArray, sym)
831-
ObjectReference.asInstanceOf[ct.bTypes.ClassBType]
807+
ObjectRef.asInstanceOf[ct.bTypes.ClassBType]
832808
}
833809

834810
tp.widenDealias match {
@@ -861,8 +837,8 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
861837
"If possible, please file a bug on https://github.com/lampepfl/dotty/issues")
862838

863839
tp match {
864-
case tp: ThisType if tp.cls == defn.ArrayClass => ObjectReference.asInstanceOf[ct.bTypes.ClassBType] // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test
865-
case tp: ThisType => storage.getClassBTypeAndRegisterInnerClass(tp.cls)
840+
case tp: ThisType if tp.cls == defn.ArrayClass => ObjectRef.asInstanceOf[ct.bTypes.ClassBType] // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test
841+
case tp: ThisType => storage.getClassBType(tp.cls)
866842
// case t: SingletonType => primitiveOrClassToBType(t.classSymbol)
867843
case t: SingletonType => typeToTypeKind(t.underlying)(ct)(storage)
868844
case t: RefinedType => typeToTypeKind(t.parent)(ct)(storage) //parents.map(_.toTypeKind(ct)(storage).asClassBType).reduceLeft((a, b) => a.jvmWiseLUB(b))

0 commit comments

Comments
 (0)