Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 29 additions & 40 deletions compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,12 @@ trait BCodeHelpers(val backendUtils: BackendUtils)(using ctx: Context) extends B
*
* @param sym The symbol for which to generate a signature.
* @param owner The owner of `sym`.
* @param descriptor The descriptor of the symbol; the signature is unnecessary if they are equal.
* @return The generic signature of `sym` before erasure, as specified in the Java Virtual
* Machine Specification, §4.3.4, or `null` if `sym` doesn't need a generic signature.
* @see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.4
*/
def getGenericSignature(sym: Symbol, owner: Symbol): String | Null = {
def getGenericSignature(sym: Symbol, owner: Symbol, descriptor: String | Null): String | Null = {
atPhase(erasurePhase) {
// Finding the member's type is nontrivial because of erasure and how it interacts with other phases.
def computeMemberType(): Type = {
Expand Down Expand Up @@ -345,7 +346,11 @@ trait BCodeHelpers(val backendUtils: BackendUtils)(using ctx: Context) extends B
owner.denot.thisType.memberInfo(sym)
}

getGenericSignatureHelper(sym, owner, computeMemberType()).orNull
if ctx.base.settings.XnoGenericSig.value then null
else
val genSig = getGenericSignatureHelper(sym, owner, computeMemberType()).orNull
if genSig == descriptor then null
else genSig
}
}

Expand Down Expand Up @@ -375,12 +380,12 @@ trait BCodeHelpers(val backendUtils: BackendUtils)(using ctx: Context) extends B
)

// TODO needed? for(ann <- m.annotations) { ann.symbol.initialize }
val jgensig = getStaticForwarderGenericSignature(m, module)
val jReturnType = ts.toTypeKind(methodInfo.resultType)
val mdesc = MethodBType(paramJavaTypes, jReturnType).descriptor
val jgensig = getStaticForwarderGenericSignature(m, module, mdesc)
val (throws, others) = m.annotations.partition(_.symbol eq defn.ThrowsAnnot)
val thrownExceptions: List[String] = getExceptions(throws)

val jReturnType = ts.toTypeKind(methodInfo.resultType)
val mdesc = MethodBType(paramJavaTypes, jReturnType).descriptor
val mirrorMethodName = m.javaSimpleName
val lengthOk = if jgensig ne null then BCodeUtils.checkConstantStringLength(jgensig)
else BCodeUtils.checkConstantStringLength(mirrorMethodName, mdesc)
Expand Down Expand Up @@ -639,22 +644,17 @@ trait BCodeHelpers(val backendUtils: BackendUtils)(using ctx: Context) extends B
} // end of trait JAndroidBuilder

private def getGenericSignatureHelper(sym: Symbol, owner: Symbol, memberTpe: Type)(using Context): Option[String] = {
if (needsGenericSignature(sym)) {
val erasedTypeSym = TypeErasure.fullErasure(sym.denot.info).typeSymbol
if (erasedTypeSym.isPrimitiveValueClass) {
// Suppress signatures for symbols whose types erase in the end to primitive
// value types. This is needed to fix #7416.
None
} else {
val jsOpt = GenericSignatures.javaSig(sym, memberTpe)
if (ctx.settings.XverifySignatures.value) {
jsOpt.foreach(verifySignature(sym, _))
}

jsOpt
}
} else {
val erasedTypeSym = TypeErasure.fullErasure(sym.denot.info).typeSymbol
if (erasedTypeSym.isPrimitiveValueClass) {
// Suppress signatures for symbols whose types erase in the end to primitive
// value types. This is needed to fix #7416.
None
} else {
val jsOpt = GenericSignatures.javaSig(sym, memberTpe)
if (ctx.settings.XverifySignatures.value) {
jsOpt.foreach(verifySignature(sym, _))
}
jsOpt
}
}

Expand Down Expand Up @@ -686,32 +686,21 @@ trait BCodeHelpers(val backendUtils: BackendUtils)(using ctx: Context) extends B
}
}

// @M don't generate java generics sigs for (members of) implementation
// classes, as they are monomorphic (TODO: ok?)
private final def needsGenericSignature(sym: Symbol): Boolean = !(
// pp: this condition used to include sym.hasexpandedname, but this leads
// to the total loss of generic information if a private member is
// accessed from a closure: both the field and the accessor were generated
// without it. This is particularly bad because the availability of
// generic information could disappear as a consequence of a seemingly
// unrelated change.
ctx.base.settings.XnoGenericSig.value
|| sym.is(Artifact)
|| sym.isAllOf(LiftedMethod)
|| sym.is(Bridge)
)

private def getStaticForwarderGenericSignature(sym: Symbol, moduleClass: Symbol): String = {
private def getStaticForwarderGenericSignature(sym: Symbol, moduleClass: Symbol, descriptor: String | Null): String | Null = {
// scala/bug#3452 Static forwarder generation uses the same erased signature as the method if forwards to.
// By rights, it should use the signature as-seen-from the module class, and add suitable
// primitive and value-class boxing/unboxing.
// But for now, just like we did in mixin, we just avoid writing a wrong generic signature
// (one that doesn't erase to the actual signature). See run/t3452b for a test case.

val memberTpe = atPhase(erasurePhase) { moduleClass.denot.thisType.memberInfo(sym) }
val erasedMemberType = ElimErasedValueType.elimEVT(TypeErasure.transformInfo(sym, memberTpe))
if (erasedMemberType =:= sym.denot.info)
getGenericSignatureHelper(sym, moduleClass, memberTpe).orNull
if !ctx.base.settings.XnoGenericSig.value then
val memberTpe = atPhase(erasurePhase) { moduleClass.denot.thisType.memberInfo(sym) }
val erasedMemberType = ElimErasedValueType.elimEVT(TypeErasure.transformInfo(sym, memberTpe))
if (erasedMemberType =:= sym.denot.info)
val gensig = getGenericSignatureHelper(sym, moduleClass, memberTpe).orNull
if gensig == descriptor then null
else gensig
else null
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not pretty, but this method belongs in the lowest circle of Hell anyway and should disappear if I ever have the courage to clean up mirror generic signature generation.

else null
}

Expand Down
11 changes: 6 additions & 5 deletions compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ trait BCodeSkelBuilder(using ctx: Context) extends BCodeHelpers {

val flags = BCodeUtils.javaFlags(claszSymbol)

val thisSignature = getGenericSignature(claszSymbol, claszSymbol.owner)
val thisSignature = getGenericSignature(claszSymbol, claszSymbol.owner, null)
val lengthOk = if thisSignature ne null then BCodeUtils.checkConstantStringLength(thisSignature)
else BCodeUtils.checkConstantStringLength(thisName)
if !lengthOk then
Expand Down Expand Up @@ -423,7 +423,8 @@ trait BCodeSkelBuilder(using ctx: Context) extends BCodeHelpers {
* No code is needed for this module symbol.
*/
for (f <- claszSymbol.info.decls.filter(p => p.isTerm && !p.is(Method))) {
val javagensig = getGenericSignature(f, claszSymbol)
val descriptor = symInfoTK(f).descriptor
val javagensig = getGenericSignature(f, claszSymbol, descriptor)
val flags = javaFieldFlags(f)

assert(!f.isStaticMember || !claszSymbol.is(Trait) || !f.is(Mutable),
Expand All @@ -432,7 +433,7 @@ trait BCodeSkelBuilder(using ctx: Context) extends BCodeHelpers {
val jfield = new asm.tree.FieldNode(
flags,
f.javaSimpleName,
symInfoTK(f).descriptor,
descriptor,
javagensig,
null // no initial value
)
Expand Down Expand Up @@ -736,15 +737,15 @@ trait BCodeSkelBuilder(using ctx: Context) extends BCodeHelpers {
*/
private def initJMethod(flags: Int, params: List[Symbol]): Unit = {

val jgensig = getGenericSignature(methSymbol, claszSymbol)
val mdesc = ts.asmMethodType(methSymbol).descriptor
val jgensig = getGenericSignature(methSymbol, claszSymbol, mdesc)
val (excs, others) = methSymbol.annotations.partition(_.symbol eq defn.ThrowsAnnot)
val thrownExceptions: List[String] = getExceptions(excs)

val bytecodeName =
if (isMethSymStaticCtor) CLASS_CONSTRUCTOR_NAME
else jMethodName

val mdesc = ts.asmMethodType(methSymbol).descriptor
val lengthOk = if jgensig ne null then BCodeUtils.checkConstantStringLength(jgensig)
else BCodeUtils.checkConstantStringLength(bytecodeName, mdesc)
if !lengthOk then
Expand Down
Loading