Skip to content

Commit a447c5b

Browse files
authored
Merge pull request #2322 from dotty-staging/change-backend-names
Change backend name handling
2 parents fa13f8d + c3cc84f commit a447c5b

File tree

10 files changed

+70
-39
lines changed

10 files changed

+70
-39
lines changed

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

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import Decorators._
3030
import tpd._
3131

3232
import scala.tools.asm
33-
import StdNames.nme
33+
import StdNames.{nme, str}
3434
import NameOps._
3535
import NameKinds.DefaultGetterName
3636
import dotty.tools.dotc.core
@@ -161,7 +161,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
161161
def boxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses().map{x => // @darkdimius Are you sure this should be a def?
162162
(x, Erasure.Boxing.boxMethod(x.asClass))
163163
}.toMap
164-
def unboxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses().map(x => (x, Erasure.Boxing.unboxMethod(x.asClass))).toMap
164+
def unboxMethods: Map[Symbol, Symbol] =
165+
defn.ScalaValueClasses().map(x => (x, Erasure.Boxing.unboxMethod(x.asClass))).toMap
165166

166167
override def isSyntheticArrayConstructor(s: Symbol) = {
167168
s eq defn.newArrayMethod
@@ -244,15 +245,15 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
244245
case ClazzTag => av.visit(name, const.typeValue.toTypeKind(bcodeStore)(innerClasesStore).toASMType)
245246
case EnumTag =>
246247
val edesc = innerClasesStore.typeDescriptor(const.tpe.asInstanceOf[bcodeStore.int.Type]) // the class descriptor of the enumeration class.
247-
val evalue = const.symbolValue.name.toString // value the actual enumeration value.
248+
val evalue = const.symbolValue.name.mangledString // value the actual enumeration value.
248249
av.visitEnum(name, edesc, evalue)
249250
}
250251
case t: TypeApply if (t.fun.symbol == Predef_classOf) =>
251252
av.visit(name, t.args.head.tpe.classSymbol.denot.info.toTypeKind(bcodeStore)(innerClasesStore).toASMType)
252253
case t: tpd.Select =>
253254
if (t.symbol.denot.is(Flags.Enum)) {
254255
val edesc = innerClasesStore.typeDescriptor(t.tpe.asInstanceOf[bcodeStore.int.Type]) // the class descriptor of the enumeration class.
255-
val evalue = t.symbol.name.toString // value the actual enumeration value.
256+
val evalue = t.symbol.name.mangledString // value the actual enumeration value.
256257
av.visitEnum(name, edesc, evalue)
257258
} else {
258259
assert(toDenot(t.symbol).name.is(DefaultGetterName)) // this should be default getter. do not emmit.
@@ -262,8 +263,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
262263
for(arg <- t.elems) { emitArgument(arrAnnotV, null, arg, bcodeStore)(innerClasesStore) }
263264
arrAnnotV.visitEnd()
264265

265-
case Apply(fun, args) if (fun.symbol == defn.ArrayClass.primaryConstructor ||
266-
(toDenot(fun.symbol).owner == defn.ArrayClass.linkedClass && fun.symbol.name == nme_apply)) =>
266+
case Apply(fun, args) if fun.symbol == defn.ArrayClass.primaryConstructor ||
267+
toDenot(fun.symbol).owner == defn.ArrayClass.linkedClass && fun.symbol.name == nme_apply =>
267268
val arrAnnotV: AnnotationVisitor = av.visitArray(name)
268269

269270
var actualArgs = if (fun.tpe.isInstanceOf[ImplicitMethodType]) {
@@ -311,7 +312,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
311312
private def emitAssocs(av: asm.AnnotationVisitor, assocs: List[(Name, Object)], bcodeStore: BCodeHelpers)
312313
(innerClasesStore: bcodeStore.BCInnerClassGen) = {
313314
for ((name, value) <- assocs)
314-
emitArgument(av, name.toString, value.asInstanceOf[Tree], bcodeStore)(innerClasesStore)
315+
emitArgument(av, name.mangledString, value.asInstanceOf[Tree], bcodeStore)(innerClasesStore)
315316
av.visitEnd()
316317
}
317318

@@ -360,9 +361,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
360361
else clazz.getName
361362
}
362363

363-
def requiredClass[T](implicit evidence: ClassTag[T]): Symbol = {
364+
def requiredClass[T](implicit evidence: ClassTag[T]): Symbol =
364365
ctx.requiredClass(erasureString(evidence.runtimeClass).toTermName)
365-
}
366366

367367
def requiredModule[T](implicit evidence: ClassTag[T]): Symbol = {
368368
val moduleName = erasureString(evidence.runtimeClass)
@@ -404,16 +404,15 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
404404
def newAnyRefMap[K <: AnyRef, V](): mutable.AnyRefMap[K, V] = new mutable.AnyRefMap[K, V]()
405405
def newWeakMap[K, V](): mutable.WeakHashMap[K, V] = new mutable.WeakHashMap[K, V]()
406406
def recordCache[T <: Clearable](cache: T): T = cache
407-
def newWeakSet[K <: AnyRef](): WeakHashSet[K] = new WeakHashSet[K]()
407+
def newWeakSet[K >: Null <: AnyRef](): WeakHashSet[K] = new WeakHashSet[K]()
408408
def newMap[K, V](): mutable.HashMap[K, V] = new mutable.HashMap[K, V]()
409409
def newSet[K](): mutable.Set[K] = new mutable.HashSet[K]
410410
}
411411

412+
val MODULE_INSTANCE_FIELD: String = str.MODULE_INSTANCE_FIELD
412413

413-
414-
val MODULE_INSTANCE_FIELD: String = nme.MODULE_INSTANCE_FIELD.toString
415-
416-
def internalNameString(offset: Int, length: Int): String = new String(Names.chrs, offset, length)
414+
def dropModule(str: String) =
415+
if (!str.isEmpty && str.last == '$') str.take(str.length - 1) else str
417416

418417
def newTermName(prefix: String): Name = prefix.toTermName
419418

@@ -424,7 +423,6 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
424423
Flags.Bridge | Flags.VBridge | Flags.Private | Flags.Macro
425424
}.bits
426425

427-
428426
def isQualifierSafeToElide(qual: Tree): Boolean = tpd.isIdempotentExpr(qual)
429427
def desugarIdent(i: Ident): Option[tpd.Select] = {
430428
i.tpe match {
@@ -537,32 +535,25 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
537535
}
538536
}
539537

540-
541538
implicit def nameHelper(n: Name): NameHelper = new NameHelper {
542-
def toTypeName: Name = n.toTypeName
543539
def isTypeName: Boolean = n.isTypeName
544-
def toTermName: Name = n.toTermName
545-
def dropModule: Name = n.stripModuleClassSuffix
546-
547-
def len: Int = n.toSimpleName.length
548-
def offset: Int = n.toSimpleName.start
549540
def isTermName: Boolean = n.isTermName
550541
def startsWith(s: String): Boolean = n.startsWith(s)
542+
def mangledString: String = n.mangledString
551543
}
552544

553-
554545
implicit def symHelper(sym: Symbol): SymbolHelper = new SymbolHelper {
555546
// names
556547
def fullName(sep: Char): String = sym.showFullName
557548
def fullName: String = sym.showFullName
558549
def simpleName: Name = sym.name
559-
def javaSimpleName: Name = toDenot(sym).name // addModuleSuffix(simpleName.dropLocal)
560-
def javaBinaryName: Name = javaClassName.replace('.', '/').toTypeName // TODO: can we make this a string? addModuleSuffix(fullNameInternal('/'))
561-
def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString
550+
def javaSimpleName: String = toDenot(sym).name.mangledString // addModuleSuffix(simpleName.dropLocal)
551+
def javaBinaryName: String = javaClassName.replace('.', '/') // TODO: can we make this a string? addModuleSuffix(fullNameInternal('/'))
552+
def javaClassName: String = toDenot(sym).fullName.mangledString // addModuleSuffix(fullNameInternal('.')).toString
562553
def name: Name = sym.name
563-
def rawname: Name = {
554+
def rawname: String = {
564555
val original = toDenot(sym).initial
565-
sym.name(ctx.withPhase(original.validFor.phaseId))
556+
sym.name(ctx.withPhase(original.validFor.phaseId)).mangledString
566557
}
567558

568559
// types
@@ -675,9 +666,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
675666
}
676667
def enclClass: Symbol = toDenot(sym).enclosingClass
677668
def linkedClassOfClass: Symbol = linkedClass
678-
def linkedClass: Symbol = {
679-
toDenot(sym)(ctx).linkedClass(ctx)
680-
} //exitingPickler(sym.linkedClassOfClass)
669+
def linkedClass: Symbol = toDenot(sym)(ctx).linkedClass(ctx) //exitingPickler(sym.linkedClassOfClass)
681670
def companionClass: Symbol = toDenot(sym).companionClass
682671
def companionModule: Symbol = toDenot(sym).companionModule
683672
def companionSymbol: Symbol = if (sym is Flags.Module) companionClass else companionModule

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
202202

203203
if (claszSymbol.isClass) // @DarkDimius is this test needed here?
204204
for (binary <- ctx.compilationUnit.pickled.get(claszSymbol.asClass)) {
205-
val dataAttr = new CustomAttr(nme.TASTYATTR.toString, binary)
205+
val dataAttr = new CustomAttr(nme.TASTYATTR.mangledString, binary)
206206
val store = if (mirrorC ne null) mirrorC else plainC
207207
store.visitAttribute(dataAttr)
208208
if (ctx.settings.emitTasty.value) {

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ object Config {
4949
*/
5050
final val checkNoSkolemsInInfo = false
5151

52+
/** Check that Name#toString is not called directly from backend by analyzing
53+
* the stack trace of each toString call on names. This is very expensive,
54+
* so not suitable for continuous testing. But it can be used to find a problem
55+
* when running a specific test.
56+
*/
57+
final val checkBackendNames = false
58+
5259
/** Type comparer will fail with an assert if the upper bound
5360
* of a constrained parameter becomes Nothing. This should be turned
5461
* on only for specific debugging as normally instantiation to Nothing

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ object Denotations {
582582
def hasUniqueSym: Boolean
583583
protected def newLikeThis(symbol: Symbol, info: Type): SingleDenotation
584584

585-
final def signature(implicit ctx: Context): Signature = {
585+
final def signature(implicit ctx: Context): Signature =
586586
if (isType) Signature.NotAMethod // don't force info if this is a type SymDenotation
587587
else info match {
588588
case info: MethodicType =>
@@ -594,7 +594,6 @@ object Denotations {
594594
}
595595
case _ => Signature.NotAMethod
596596
}
597-
}
598597

599598
def derivedSingleDenotation(symbol: Symbol, info: Type)(implicit ctx: Context): SingleDenotation =
600599
if ((symbol eq this.symbol) && (info eq this.info)) this

compiler/src/dotty/tools/dotc/core/Names.scala

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import collection.mutable.{ Builder, StringBuilder, AnyRefMap }
1414
import collection.immutable.WrappedString
1515
import collection.generic.CanBuildFrom
1616
import util.{DotClass, SimpleMap}
17+
import config.Config
1718
import java.util.HashMap
1819

1920
//import annotation.volatile
@@ -67,6 +68,7 @@ object Names {
6768
def asSimpleName: SimpleTermName
6869
def toSimpleName: SimpleTermName
6970
def mangled: Name
71+
def mangledString: String = mangled.toString
7072

7173
def rewrite(f: PartialFunction[Name, Name]): ThisName
7274
def collect[T](f: PartialFunction[Name, T]): Option[T]
@@ -287,7 +289,40 @@ object Names {
287289
override def hashCode: Int = start
288290

289291
override def toString =
290-
if (length == 0) "" else new String(chrs, start, length)
292+
if (length == 0) ""
293+
else {
294+
if (Config.checkBackendNames) {
295+
if (!toStringOK) {
296+
// We print the stacktrace instead of doing an assert directly,
297+
// because asserts are caught in exception handlers which might
298+
// cause other failures. In that case the first, important failure
299+
// is lost.
300+
println("Backend should not call Name#toString, Name#mangledString should be used instead.")
301+
new Error().printStackTrace()
302+
assert(false)
303+
}
304+
}
305+
new String(chrs, start, length)
306+
}
307+
308+
/** It's OK to take a toString if the stacktrace does not occur a method
309+
* in GenBCode or it also contains one of the whitelisted methods below.
310+
*/
311+
private def toStringOK = {
312+
val trace = Thread.currentThread.getStackTrace
313+
!trace.exists(_.getClassName.endsWith("GenBCode")) ||
314+
trace.exists(elem =>
315+
List(
316+
"mangledString",
317+
"toSimpleName",
318+
"decode",
319+
"unmangle",
320+
"dotty$tools$dotc$core$NameOps$NameDecorator$$functionArityFor$extension",
321+
"dotty$tools$dotc$typer$Checking$CheckNonCyclicMap$$apply",
322+
"$plus$plus",
323+
"readConstant")
324+
.contains(elem.getMethodName))
325+
}
291326

292327
def debugString: String = toString
293328
}

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ object StdNames {
3333
final val INTERPRETER_LINE_PREFIX = "line"
3434
final val INTERPRETER_VAR_PREFIX = "res"
3535
final val INTERPRETER_WRAPPER_SUFFIX = "$object"
36+
final val MODULE_INSTANCE_FIELD = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
3637

3738
final val Function = "Function"
3839
final val ImplicitFunction = "ImplicitFunction"

compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ class SymbolLoaders {
220220
if (!sourceModule.isCompleted)
221221
sourceModule.completer.complete(sourceModule)
222222

223-
val packageName = if (root.isEffectiveRoot) "" else root.fullName.toString
223+
val packageName = if (root.isEffectiveRoot) "" else root.fullName.mangledString
224224

225225
enterFlatClasses = Some { ctx =>
226226
enterFlatClasses = None

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ class ClassfileParser(
677677
for (entry <- innerClasses.values) {
678678
// create a new class member for immediate inner classes
679679
if (entry.outerName == currentClassName) {
680-
val file = ctx.platform.classPath.findClassFile(entry.externalName.toString) getOrElse {
680+
val file = ctx.platform.classPath.findClassFile(entry.externalName.mangledString) getOrElse {
681681
throw new AssertionError(entry.externalName)
682682
}
683683
enterClassAndModule(entry, file, entry.jflags)

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class TreeChecker extends Phase with SymTransformer {
6363
val NoSuperClass = Trait | Package
6464

6565
def testDuplicate(sym: Symbol, registry: mutable.Map[String, Symbol], typ: String)(implicit ctx: Context) = {
66-
val name = sym.fullName.toString
66+
val name = sym.fullName.mangledString
6767
if (this.flatClasses && registry.contains(name))
6868
printError(s"$typ defined twice $sym ${sym.id} ${registry(name).id}")
6969
registry(name) = sym

0 commit comments

Comments
 (0)