Skip to content

Commit 688bf0f

Browse files
committed
Avoid Names for descriptors, generic sigs, and string constants
We can just keep these are short-lived Strings, rather than interning them into the Name table for the entire lifetime of Global.
1 parent 4a64e1f commit 688bf0f

File tree

1 file changed

+35
-27
lines changed

1 file changed

+35
-27
lines changed

src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ abstract class ClassfileParser {
9595
private def readMethodFlags() = JavaAccFlags methodFlags u2
9696
private def readFieldFlags() = JavaAccFlags fieldFlags u2
9797
private def readTypeName() = readName().toTypeName
98-
private def readName() = pool getName u2
98+
private def readName() = pool.getName(u2).name
9999
private def readType() = pool getType u2
100100

101101
private object unpickler extends scala.reflect.internal.pickling.UnPickler {
@@ -175,7 +175,7 @@ abstract class ClassfileParser {
175175
protected val len = u2
176176
protected val starts = new Array[Int](len)
177177
protected val values = new Array[AnyRef](len)
178-
protected val internalized = new Array[Name](len)
178+
protected val internalized = new Array[NameOrString](len)
179179

180180
{ var i = 1
181181
while (i < starts.length) {
@@ -206,28 +206,35 @@ abstract class ClassfileParser {
206206
else this errorBadTag start
207207
}
208208

209+
class NameOrString(val value: String) {
210+
private var _name: Name = null
211+
def name: Name = {
212+
if (_name eq null) _name = TermName(value)
213+
_name
214+
}
215+
}
209216
/** Return the name found at given index. */
210-
def getName(index: Int): Name = (
217+
def getName(index: Int): NameOrString = (
211218
if (index <= 0 || len <= index) errorBadIndex(index)
212219
else values(index) match {
213-
case name: Name => name
220+
case name: NameOrString => name
214221
case _ =>
215222
val start = firstExpecting(index, CONSTANT_UTF8)
216223
val len = in.getChar(start).toInt
217-
recordAtIndex(TermName(fromMUTF8(in.buf, start, len + 2)), index)
224+
recordAtIndex(new NameOrString(fromMUTF8(in.buf, start, len + 2)), index)
218225
}
219226
)
220227

221228
private def fromMUTF8(bytes: Array[Byte], offset: Int, len: Int): String =
222229
new DataInputStream(new ByteArrayInputStream(bytes, offset, len)).readUTF
223230

224231
/** Return the name found at given index in the constant pool, with '/' replaced by '.'. */
225-
def getExternalName(index: Int): Name = {
232+
def getExternalName(index: Int): NameOrString = {
226233
if (index <= 0 || len <= index)
227234
errorBadIndex(index)
228235

229236
if (internalized(index) == null)
230-
internalized(index) = getName(index).replace('/', '.')
237+
internalized(index) = new NameOrString(getName(index).value.replace('/', '.'))
231238

232239
internalized(index)
233240
}
@@ -237,7 +244,7 @@ abstract class ClassfileParser {
237244
values(index) match {
238245
case sym: Symbol => sym
239246
case _ =>
240-
val result = getClassName(index) match {
247+
val result = getClassName(index).name match {
241248
case name if nme.isModuleName(name) => rootMirror getModuleByName name.dropModule
242249
case name => classNameToSymbol(name)
243250
}
@@ -248,7 +255,7 @@ abstract class ClassfileParser {
248255
/** Return the external name of the class info structure found at 'index'.
249256
* Use 'getClassSymbol' if the class is sure to be a top-level class.
250257
*/
251-
def getClassName(index: Int): Name = {
258+
def getClassName(index: Int): NameOrString = {
252259
val start = firstExpecting(index, CONSTANT_CLASS)
253260
getExternalName((in getChar start).toInt)
254261
}
@@ -267,14 +274,14 @@ abstract class ClassfileParser {
267274
val start = firstExpecting(index, CONSTANT_NAMEANDTYPE)
268275
val name = getName(in.getChar(start).toInt)
269276
// create a dummy symbol for method types
270-
val dummy = ownerTpe.typeSymbol.newMethod(name.toTermName, ownerTpe.typeSymbol.pos)
277+
val dummy = ownerTpe.typeSymbol.newMethod(name.name.toTermName, ownerTpe.typeSymbol.pos)
271278
val tpe = getType(dummy, in.getChar(start + 2).toInt)
272279
// fix the return type, which is blindly set to the class currently parsed
273280
val restpe = tpe match {
274-
case MethodType(formals, _) if name == nme.CONSTRUCTOR => MethodType(formals, ownerTpe)
275-
case _ => tpe
281+
case MethodType(formals, _) if name.name == nme.CONSTRUCTOR => MethodType(formals, ownerTpe)
282+
case _ => tpe
276283
}
277-
((name, restpe))
284+
((name.name, restpe))
278285
}
279286
}
280287

@@ -289,21 +296,21 @@ abstract class ClassfileParser {
289296
case cls: Symbol => cls.tpe_*
290297
case _ =>
291298
val name = getClassName(index)
292-
name charAt 0 match {
293-
case ARRAY_TAG => recordAtIndex(sigToType(null, name), index)
294-
case _ => recordAtIndex(classNameToSymbol(name), index).tpe_*
299+
name.value.charAt(0) match {
300+
case ARRAY_TAG => recordAtIndex(sigToType(null, name.value), index)
301+
case _ => recordAtIndex(classNameToSymbol(name.name), index).tpe_*
295302
}
296303
}
297304
}
298305

299306
def getType(index: Int): Type = getType(null, index)
300-
def getType(sym: Symbol, index: Int): Type = sigToType(sym, getExternalName(index))
307+
def getType(sym: Symbol, index: Int): Type = sigToType(sym, getExternalName(index).value)
301308
def getSuperClass(index: Int): Symbol = if (index == 0) AnyClass else getClassSymbol(index) // the only classfile that is allowed to have `0` in the super_class is java/lang/Object (see jvm spec)
302309

303310
private def createConstant(index: Int): Constant = {
304311
val start = starts(index)
305312
Constant((in.buf(start).toInt: @switch) match {
306-
case CONSTANT_STRING => getName(in.getChar(start + 1).toInt).toString
313+
case CONSTANT_STRING => getName(in.getChar(start + 1).toInt).value
307314
case CONSTANT_INTEGER => in.getInt(start + 1)
308315
case CONSTANT_FLOAT => in.getFloat(start + 1)
309316
case CONSTANT_LONG => in.getLong(start + 1)
@@ -451,7 +458,7 @@ abstract class ClassfileParser {
451458

452459
val jflags = readClassFlags()
453460
val classNameIndex = u2
454-
currentClass = pool.getClassName(classNameIndex)
461+
currentClass = pool.getClassName(classNameIndex).name
455462

456463
// Ensure that (top-level) classfiles are in the correct directory
457464
val isTopLevel = !(currentClass containsChar '$') // Java class name; *don't* try to to use Scala name decoding (scala/bug#7532)
@@ -650,7 +657,8 @@ abstract class ClassfileParser {
650657
}
651658
}
652659

653-
private def sigToType(sym: Symbol, sig: Name): Type = {
660+
private def sigToType(sym: Symbol, sig: String): Type = {
661+
val sigChars = sig.toCharArray
654662
var index = 0
655663
val end = sig.length
656664
def accept(ch: Char): Unit = {
@@ -660,7 +668,7 @@ abstract class ClassfileParser {
660668
def subName(isDelimiter: Char => Boolean): Name = {
661669
val start = index
662670
while (!isDelimiter(sig.charAt(index))) { index += 1 }
663-
sig.subName(start, index)
671+
newTermName(sigChars, start, index - start)
664672
}
665673
def sig2type(tparams: immutable.Map[Name,Symbol], skiptvs: Boolean): Type = {
666674
val tag = sig.charAt(index); index += 1
@@ -842,7 +850,7 @@ abstract class ClassfileParser {
842850
attrName match {
843851
case tpnme.SignatureATTR =>
844852
val sig = pool.getExternalName(u2)
845-
val newType = sigToType(sym, sig)
853+
val newType = sigToType(sym, sig.value)
846854
sym.setInfo(newType)
847855

848856
case tpnme.SyntheticATTR =>
@@ -879,7 +887,7 @@ abstract class ClassfileParser {
879887
val access = u2
880888

881889
val name =
882-
if ((access & ACC_SYNTHETIC) == 0) rawname.encode
890+
if ((access & ACC_SYNTHETIC) == 0) rawname.name.encode
883891
else nme.NO_NAME
884892

885893
paramNames += name
@@ -985,7 +993,7 @@ abstract class ClassfileParser {
985993
val index = u2
986994
tag match {
987995
case STRING_TAG =>
988-
Some(LiteralAnnotArg(Constant(pool.getName(index).toString)))
996+
Some(LiteralAnnotArg(Constant(pool.getName(index).value)))
989997
case BOOL_TAG | BYTE_TAG | CHAR_TAG | SHORT_TAG | INT_TAG |
990998
LONG_TAG | FLOAT_TAG | DOUBLE_TAG =>
991999
Some(LiteralAnnotArg(pool.getConstant(index)))
@@ -1259,9 +1267,9 @@ abstract class ClassfileParser {
12591267

12601268
/** An entry in the InnerClasses attribute of this class file. */
12611269
case class InnerClassEntry(external: Int, outer: Int, name: Int, jflags: JavaAccFlags) {
1262-
def externalName = pool getClassName external
1263-
def outerName = pool getClassName outer
1264-
def originalName = pool getName name
1270+
def externalName = pool.getClassName(external).name
1271+
def outerName = pool.getClassName(outer).name
1272+
def originalName = pool.getName(name).name
12651273
def isModule = originalName.isTermName
12661274
def scope = if (jflags.isStatic) staticScope else instanceScope
12671275
def enclosing = if (jflags.isStatic) enclModule else enclClass

0 commit comments

Comments
 (0)