Skip to content

Commit c3fcd4e

Browse files
committed
Micro optimise Symbol#fullName
The old approach of recursively calling `fullNameAsName` creates a lot of garbage for intermediate results, in addition to needless interning of those results into the name table. This commit instead creates a string buffer of the correct capacity and writes the component names directly into this. I compared old and new approaches and this shows a 2x speedup. ``` scala> val th = ichi.bench.Thyme.warmed(verbose = print) th: ichi.bench.Thyme = ichi.bench.Thyme@1643e817 scala> val w_old = th.Warm(sym.fullNameAsNameOld('.')) w_old: th.Warm[$r.intp.global.Name] = ichi.bench.Thyme$Warm@7a8d001b scala> val w_new = th.Warm(sym.fullNameAsName('.')) w_new: th.Warm[$r.intp.global.Name] = ichi.bench.Thyme$Warm@1ec14586 scala> th.pbenchOffWarm("", x => println(x))(w_old, 10, "old")(w_new, 10, "new") Benchmark comparison (in 4.084 s) old vs new Significantly different (p ~= 0) Time ratio: 0.53572 95% CI 0.51618 - 0.55525 (n=20) old 64.54 ns 95% CI 62.41 ns - 66.67 ns new 34.57 ns 95% CI 34.04 ns - 35.11 ns res3: $r.intp.global.Name = scala.collection.parallel.mutable.ParSeq ``` It is still expensive enough that we should still consider caching. The call to full name in `classBTypeFromSymbol` in the new backed is a prime candidate for optimization.
1 parent ef4ed49 commit c3fcd4e

1 file changed

Lines changed: 25 additions & 13 deletions

File tree

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,27 +1256,39 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
12561256
/** These should be moved somewhere like JavaPlatform.
12571257
*/
12581258
def javaSimpleName: Name = addModuleSuffix(simpleName.dropLocal)
1259-
def javaBinaryName: Name = addModuleSuffix(fullNameInternal('/'))
1260-
def javaClassName: String = addModuleSuffix(fullNameInternal('.')).toString
1259+
def javaBinaryName: Name = name.newName(javaBinaryNameString)
1260+
def javaBinaryNameString: String = fullName('/', moduleSuffix)
1261+
def javaClassName: String = fullName('.', moduleSuffix)
12611262

12621263
/** The encoded full path name of this symbol, where outer names and inner names
12631264
* are separated by `separator` characters.
12641265
* Never translates expansions of operators back to operator symbol.
12651266
* Never adds id.
12661267
* Drops package objects.
12671268
*/
1268-
final def fullName(separator: Char): String = fullNameAsName(separator).toString
1269-
1270-
/** Doesn't drop package objects, for those situations (e.g. classloading)
1271-
* where the true path is needed.
1272-
*/
1273-
private def fullNameInternal(separator: Char): Name = (
1274-
if (isRoot || isRootPackage || this == NoSymbol) name
1275-
else if (owner.isEffectiveRoot) name
1276-
else effectiveOwner.enclClass.fullNameAsName(separator) append (separator, name)
1277-
)
1269+
final def fullName(separator: Char): String = fullName(separator, "")
1270+
1271+
private def fullName(separator: Char, suffix: CharSequence): String = {
1272+
var b: java.lang.StringBuffer = null
1273+
def loop(size: Int, sym: Symbol): Unit = {
1274+
val symName = sym.name
1275+
val nSize = symName.length - (if (symName.endsWith(nme.LOCAL_SUFFIX_STRING)) 1 else 0)
1276+
if (sym.isRoot || sym.isRootPackage || sym == NoSymbol || sym.owner.isEffectiveRoot) {
1277+
val capacity = size + nSize
1278+
b = new java.lang.StringBuffer(capacity)
1279+
b.append(chrs, symName.start, nSize)
1280+
} else {
1281+
loop(size + nSize + 1, sym.effectiveOwner.enclClass)
1282+
b.append(separator)
1283+
b.append(chrs, symName.start, nSize)
1284+
}
1285+
}
1286+
loop(suffix.length(), this)
1287+
b.append(suffix)
1288+
b.toString
1289+
}
12781290

1279-
def fullNameAsName(separator: Char): Name = fullNameInternal(separator).dropLocal
1291+
def fullNameAsName(separator: Char): Name = name.newName(fullName(separator, ""))
12801292

12811293
/** The encoded full path name of this symbol, where outer names and inner names
12821294
* are separated by periods.

0 commit comments

Comments
 (0)