Skip to content

Commit ced7214

Browse files
committed
Move ICodeReader-specific logic out of ClassfileParser.
ClassfileParser contained some ICodeReader-specific logic like `forceMangledName` and `getMemberSymbol` methods. The `getMemberSymbol` method was defined in ConstantPool class because it must access some internal state of ConstantPool. In order to move that method to ICodeReader we had two options: 1. Make all internal state accessible from outside of ConstantPool class so getMemberSymbol could be implemented outside of ConstantPool hierarchy 2. Make it possible to subclass ConstantPool in ICodeReader so getMemberSymbol can be implemented in a subclass and can access internal state of ConstantPool Given the fact that getMemberSymbol mutates ConstantPool's internal state I decided that subclassing is a cleaner approach. It required significant refactoring because we had to make sure that we create an instance of proper class when initializing the `pool` variable. I ended up introducing `ConstantPoolManager` class which is essentially a mutable variable that can be reset multiple times. This change makes ClassfileParser independent from the ICodeReader and its implementation details.
1 parent 56b7c0f commit ced7214

File tree

3 files changed

+109
-95
lines changed

3 files changed

+109
-95
lines changed

src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,10 @@ abstract class SymbolLoaders {
246246
class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader with FlagAssigningCompleter {
247247
private object classfileParser extends {
248248
val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global
249-
} with ClassfileParser
249+
} with ClassfileParser {
250+
override protected type ThisConstantPool = ConstantPool
251+
override protected def newConstantPool: ThisConstantPool = new ConstantPool
252+
}
250253

251254
protected def description = "class file "+ classfile.toString
252255

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

Lines changed: 16 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,15 @@ abstract class ClassfileParser {
3030
import scala.reflect.internal.ClassfileConstants._
3131
import Flags._
3232

33+
protected type ThisConstantPool <: ConstantPool
34+
protected def newConstantPool: ThisConstantPool
35+
3336
protected var in: AbstractFileReader = _ // the class file reader
3437
protected var clazz: Symbol = _ // the class symbol containing dynamic members
3538
protected var staticModule: Symbol = _ // the module symbol containing static members
3639
protected var instanceScope: Scope = _ // the scope of all instance definitions
3740
protected var staticScope: Scope = _ // the scope of all static definitions
38-
protected var pool: ConstantPool = _ // the classfile's constant pool
41+
protected var pool: ThisConstantPool = _ // the classfile's constant pool
3942
protected var isScala: Boolean = _ // does class file describe a scala class?
4043
protected var isScalaAnnot: Boolean = _ // does class file describe a scala class with its pickled info in an annotation?
4144
protected var isScalaRaw: Boolean = _ // this class file is a scala class with no pickled info
@@ -119,7 +122,7 @@ abstract class ClassfileParser {
119122
this.isScala = false
120123

121124
parseHeader()
122-
this.pool = new ConstantPool
125+
this.pool = newConstantPool
123126
parseClass()
124127
}
125128
}
@@ -134,11 +137,14 @@ abstract class ClassfileParser {
134137
abort(s"class file ${in.file} has unknown version $major.$minor, should be at least $JAVA_MAJOR_VERSION.$JAVA_MINOR_VERSION")
135138
}
136139

137-
class ConstantPool {
138-
private val len = u2
139-
private val starts = new Array[Int](len)
140-
private val values = new Array[AnyRef](len)
141-
private val internalized = new Array[Name](len)
140+
/**
141+
* Constructor of this class should not be called directly, use `newConstantPool` instead.
142+
*/
143+
protected class ConstantPool {
144+
protected val len = u2
145+
protected val starts = new Array[Int](len)
146+
protected val values = new Array[AnyRef](len)
147+
protected val internalized = new Array[Name](len)
142148

143149
{ var i = 1
144150
while (i < starts.length) {
@@ -212,76 +218,13 @@ abstract class ClassfileParser {
212218
getExternalName((in getChar start).toInt)
213219
}
214220

215-
/** Return the symbol of the class member at `index`.
216-
* The following special cases exist:
217-
* - If the member refers to special `MODULE$` static field, return
218-
* the symbol of the corresponding module.
219-
* - If the member is a field, and is not found with the given name,
220-
* another try is made by appending `nme.LOCAL_SUFFIX_STRING`
221-
* - If no symbol is found in the right tpe, a new try is made in the
222-
* companion class, in case the owner is an implementation class.
223-
*/
224-
def getMemberSymbol(index: Int, static: Boolean): Symbol = {
225-
if (index <= 0 || len <= index) errorBadIndex(index)
226-
var f = values(index).asInstanceOf[Symbol]
227-
if (f eq null) {
228-
val start = starts(index)
229-
val first = in.buf(start).toInt
230-
if (first != CONSTANT_FIELDREF &&
231-
first != CONSTANT_METHODREF &&
232-
first != CONSTANT_INTFMETHODREF) errorBadTag(start)
233-
val ownerTpe = getClassOrArrayType(in.getChar(start + 1).toInt)
234-
debuglog("getMemberSymbol(static: " + static + "): owner type: " + ownerTpe + " " + ownerTpe.typeSymbol.originalName)
235-
val (name0, tpe0) = getNameAndType(in.getChar(start + 3).toInt, ownerTpe)
236-
debuglog("getMemberSymbol: name and tpe: " + name0 + ": " + tpe0)
237-
238-
forceMangledName(tpe0.typeSymbol.name, module = false)
239-
val (name, tpe) = getNameAndType(in.getChar(start + 3).toInt, ownerTpe)
240-
if (name == nme.MODULE_INSTANCE_FIELD) {
241-
val index = in.getChar(start + 1).toInt
242-
val name = getExternalName(in.getChar(starts(index).toInt + 1).toInt)
243-
//assert(name.endsWith("$"), "Not a module class: " + name)
244-
f = forceMangledName(name dropRight 1, module = true)
245-
if (f == NoSymbol)
246-
f = rootMirror.getModuleByName(name dropRight 1)
247-
} else {
248-
val origName = nme.unexpandedName(name)
249-
val owner = if (static) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol
250-
f = owner.info.findMember(origName, 0, 0, stableOnly = false).suchThat(_.tpe.widen =:= tpe)
251-
if (f == NoSymbol)
252-
f = owner.info.findMember(newTermName(origName + nme.LOCAL_SUFFIX_STRING), 0, 0, stableOnly = false).suchThat(_.tpe =:= tpe)
253-
if (f == NoSymbol) {
254-
// if it's an impl class, try to find it's static member inside the class
255-
if (ownerTpe.typeSymbol.isImplClass) {
256-
f = ownerTpe.findMember(origName, 0, 0, stableOnly = false).suchThat(_.tpe =:= tpe)
257-
} else {
258-
log("Couldn't find " + name + ": " + tpe + " inside: \n" + ownerTpe)
259-
f = tpe match {
260-
case MethodType(_, _) => owner.newMethod(name.toTermName, owner.pos)
261-
case _ => owner.newVariable(name.toTermName, owner.pos)
262-
}
263-
f setInfo tpe
264-
log("created fake member " + f.fullName)
265-
}
266-
}
267-
}
268-
assert(f != NoSymbol,
269-
s"could not find $name: $tpe in $ownerTpe" + (
270-
if (settings.debug.value) ownerTpe.members.mkString(", members are:\n ", "\n ", "") else ""
271-
)
272-
)
273-
values(index) = f
274-
}
275-
f
276-
}
277-
278221
/** Return a name and a type at the given index. If the type is a method
279222
* type, a dummy symbol is created in `ownerTpe`, which is used as the
280223
* owner of its value parameters. This might lead to inconsistencies,
281224
* if a symbol of the given name already exists, and has a different
282225
* type.
283226
*/
284-
private def getNameAndType(index: Int, ownerTpe: Type): (Name, Type) = {
227+
protected def getNameAndType(index: Int, ownerTpe: Type): (Name, Type) = {
285228
if (index <= 0 || len <= index) errorBadIndex(index)
286229
values(index) match {
287230
case p: ((Name @unchecked, Type @unchecked)) => p
@@ -381,35 +324,14 @@ abstract class ClassfileParser {
381324
}
382325

383326
/** Throws an exception signaling a bad constant index. */
384-
private def errorBadIndex(index: Int) =
327+
protected def errorBadIndex(index: Int) =
385328
abort(s"bad constant pool index: $index at pos: ${in.bp}")
386329

387330
/** Throws an exception signaling a bad tag at given address. */
388-
private def errorBadTag(start: Int) =
331+
protected def errorBadTag(start: Int) =
389332
abort("bad constant pool tag ${in.buf(start)} at byte $start")
390333
}
391334

392-
/** Try to force the chain of enclosing classes for the given name. Otherwise
393-
* flatten would not lift classes that were not referenced in the source code.
394-
*/
395-
def forceMangledName(name: Name, module: Boolean): Symbol = {
396-
val parts = name.decode.toString.split(Array('.', '$'))
397-
var sym: Symbol = rootMirror.RootClass
398-
399-
// was "at flatten.prev"
400-
enteringFlatten {
401-
for (part0 <- parts; if !(part0 == ""); part = newTermName(part0)) {
402-
val sym1 = enteringIcode {
403-
sym.linkedClassOfClass.info
404-
sym.info.decl(part.encode)
405-
}//.suchThat(module == _.isModule)
406-
407-
sym = sym1 orElse sym.info.decl(part.encode.toTypeName)
408-
}
409-
}
410-
sym
411-
}
412-
413335
private def loadClassSymbol(name: Name): Symbol = {
414336
val file = global.classPath findSourceFile ("" +name) getOrElse {
415337
// SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented

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

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,95 @@ abstract class ICodeReader extends ClassfileParser {
2828
var method: IMethod = NoIMethod // the current IMethod
2929
var isScalaModule = false
3030

31+
override protected type ThisConstantPool = ICodeConstantPool
32+
override protected def newConstantPool = new ICodeConstantPool
33+
34+
/** Try to force the chain of enclosing classes for the given name. Otherwise
35+
* flatten would not lift classes that were not referenced in the source code.
36+
*/
37+
def forceMangledName(name: Name, module: Boolean): Symbol = {
38+
val parts = name.decode.toString.split(Array('.', '$'))
39+
var sym: Symbol = rootMirror.RootClass
40+
41+
// was "at flatten.prev"
42+
enteringFlatten {
43+
for (part0 <- parts; if !(part0 == ""); part = newTermName(part0)) {
44+
val sym1 = enteringIcode {
45+
sym.linkedClassOfClass.info
46+
sym.info.decl(part.encode)
47+
}//.suchThat(module == _.isModule)
48+
49+
sym = sym1 orElse sym.info.decl(part.encode.toTypeName)
50+
}
51+
}
52+
sym
53+
}
54+
55+
protected class ICodeConstantPool extends ConstantPool {
56+
/** Return the symbol of the class member at `index`.
57+
* The following special cases exist:
58+
* - If the member refers to special `MODULE$` static field, return
59+
* the symbol of the corresponding module.
60+
* - If the member is a field, and is not found with the given name,
61+
* another try is made by appending `nme.LOCAL_SUFFIX_STRING`
62+
* - If no symbol is found in the right tpe, a new try is made in the
63+
* companion class, in case the owner is an implementation class.
64+
*/
65+
def getMemberSymbol(index: Int, static: Boolean): Symbol = {
66+
if (index <= 0 || len <= index) errorBadIndex(index)
67+
var f = values(index).asInstanceOf[Symbol]
68+
if (f eq null) {
69+
val start = starts(index)
70+
val first = in.buf(start).toInt
71+
if (first != CONSTANT_FIELDREF &&
72+
first != CONSTANT_METHODREF &&
73+
first != CONSTANT_INTFMETHODREF) errorBadTag(start)
74+
val ownerTpe = getClassOrArrayType(in.getChar(start + 1).toInt)
75+
debuglog("getMemberSymbol(static: " + static + "): owner type: " + ownerTpe + " " + ownerTpe.typeSymbol.originalName)
76+
val (name0, tpe0) = getNameAndType(in.getChar(start + 3).toInt, ownerTpe)
77+
debuglog("getMemberSymbol: name and tpe: " + name0 + ": " + tpe0)
78+
79+
forceMangledName(tpe0.typeSymbol.name, module = false)
80+
val (name, tpe) = getNameAndType(in.getChar(start + 3).toInt, ownerTpe)
81+
if (name == nme.MODULE_INSTANCE_FIELD) {
82+
val index = in.getChar(start + 1).toInt
83+
val name = getExternalName(in.getChar(starts(index).toInt + 1).toInt)
84+
//assert(name.endsWith("$"), "Not a module class: " + name)
85+
f = forceMangledName(name dropRight 1, module = true)
86+
if (f == NoSymbol)
87+
f = rootMirror.getModuleByName(name dropRight 1)
88+
} else {
89+
val origName = nme.unexpandedName(name)
90+
val owner = if (static) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol
91+
f = owner.info.findMember(origName, 0, 0, stableOnly = false).suchThat(_.tpe.widen =:= tpe)
92+
if (f == NoSymbol)
93+
f = owner.info.findMember(newTermName(origName + nme.LOCAL_SUFFIX_STRING), 0, 0, stableOnly = false).suchThat(_.tpe =:= tpe)
94+
if (f == NoSymbol) {
95+
// if it's an impl class, try to find it's static member inside the class
96+
if (ownerTpe.typeSymbol.isImplClass) {
97+
f = ownerTpe.findMember(origName, 0, 0, stableOnly = false).suchThat(_.tpe =:= tpe)
98+
} else {
99+
log("Couldn't find " + name + ": " + tpe + " inside: \n" + ownerTpe)
100+
f = tpe match {
101+
case MethodType(_, _) => owner.newMethod(name.toTermName, owner.pos)
102+
case _ => owner.newVariable(name.toTermName, owner.pos)
103+
}
104+
f setInfo tpe
105+
log("created fake member " + f.fullName)
106+
}
107+
}
108+
}
109+
assert(f != NoSymbol,
110+
s"could not find $name: $tpe in $ownerTpe" + (
111+
if (settings.debug.value) ownerTpe.members.mkString(", members are:\n ", "\n ", "") else ""
112+
)
113+
)
114+
values(index) = f
115+
}
116+
f
117+
}
118+
}
119+
31120
/** Read back bytecode for the given class symbol. It returns
32121
* two IClass objects, one for static members and one
33122
* for non-static members.

0 commit comments

Comments
 (0)