6
6
package scala .tools .nsc
7
7
package backend .jvm
8
8
9
- import scala .annotation .switch
10
- import scala .collection .{concurrent , mutable }
11
9
import scala .collection .concurrent .TrieMap
10
+ import scala .collection .{concurrent , mutable }
12
11
import scala .reflect .internal .util .Position
13
12
import scala .tools .asm
14
- import asm .Opcodes
13
+ import scala . tools . asm .Opcodes
15
14
import scala .tools .asm .tree ._
16
- import scala .tools .nsc .backend .jvm .BTypes .{InlineInfo , MethodInlineInfo }
15
+ import scala .tools .nsc .backend .jvm .BTypes .{InlineInfo , InternalName }
17
16
import scala .tools .nsc .backend .jvm .BackendReporting ._
18
- import scala .tools .nsc .backend .jvm .analysis .BackendUtils
19
17
import scala .tools .nsc .backend .jvm .opt ._
20
- import scala .collection .JavaConverters ._
21
- import scala .collection .mutable .ListBuffer
22
- import scala .tools .nsc .settings .ScalaSettings
23
18
24
19
/**
25
20
* The BTypes component defines The BType class hierarchy. A BType stores all type information
<
10000
/tr>@@ -30,44 +25,15 @@ import scala.tools.nsc.settings.ScalaSettings
30
25
* be queried by concurrent threads.
31
26
*/
32
27
abstract class BTypes {
33
- import BTypes .InternalName
34
-
35
- // Stages after code generation in the backend (optimizations, classfile writing) are prepared
36
- // to run in parallel on multiple classes. This object should be used for synchronizing operations
37
- // that may access the compiler frontend during these late stages.
38
- val frontendLock : AnyRef = new Object ()
39
-
40
- val backendUtils : BackendUtils [this .type ]
28
+ val postProcessorFrontendAccess : PostProcessorFrontendAccess
29
+ import postProcessorFrontendAccess .{frontendSynch , recordPerRunCache }
41
30
42
31
// Some core BTypes are required here, in class BType, where no Global instance is available.
43
32
// The Global is only available in the subclass BTypesFromSymbols. We cannot depend on the actual
44
33
// implementation (CoreBTypesProxy) here because it has members that refer to global.Symbol.
45
34
val coreBTypes : CoreBTypesProxyGlobalIndependent [this .type ]
46
35
import coreBTypes ._
47
36
48
- /**
49
- * Tools for parsing classfiles, used by the inliner.
50
- */
51
- val byteCodeRepository : ByteCodeRepository [this .type ]
52
-
53
- val localOpt : LocalOpt [this .type ]
54
-
55
- val inliner : Inliner [this .type ]
56
-
57
- val inlinerHeuristics : InlinerHeuristics [this .type ]
58
-
59
- val closureOptimizer : ClosureOptimizer [this .type ]
60
-
61
- val callGraph : CallGraph [this .type ]
62
-
63
- val backendReporting : BackendReporting
64
-
65
- // Allows to define per-run caches here and in the CallGraph component, which don't have a global
66
- def recordPerRunCache [T <: collection.generic.Clearable ](cache : T ): T
67
-
68
- // Allows access to the compiler settings for backend components that don't have a global in scope
69
- def compilerSettings : ScalaSettings
70
-
71
37
/**
72
38
* Every ClassBType is cached on construction and accessible through this method.
73
39
*
@@ -138,7 +104,7 @@ abstract class BTypes {
138
104
def addIndyLambdaImplMethod (hostClass : InternalName , handle : Seq [asm.Handle ]): Seq [asm.Handle ] = {
139
105
if (handle.isEmpty) Nil else {
140
106
val set = indyLambdaImplMethods.getOrElseUpdate(hostClass, mutable.LinkedHashSet ())
141
- if (set isEmpty) {
107
+ if (set. isEmpty) {
142
108
set ++= handle
143
109
handle
144
110
} else {
@@ -163,156 +129,6 @@ abstract class BTypes {
163
129
}
164
130
}
165
131
166
- /**
167
- * Obtain the BType for a type descriptor or internal name. For class descriptors, the ClassBType
168
- * is constructed by parsing the corresponding classfile.
169
- *
170
- * Some JVM operations use either a full descriptor or only an internal name. Example:
171
- * ANEWARRAY java/lang/String // a new array of strings (internal name for the String class)
172
- * ANEWARRAY [Ljava/lang/String; // a new array of array of string (full descriptor for the String class)
173
- *
174
- * This method supports both descriptors and internal names.
175
- */
176
- def bTypeForDescriptorOrInternalNameFromClassfile (desc : String ): BType = (desc(0 ): @ switch) match {
177
- case 'V' => UNIT
178
- case 'Z' => BOOL
179
- case 'C' => CHAR
180
- case 'B' => BYTE
181
- case 'S' => SHORT
182
- case 'I' => INT
183
- case 'F' => FLOAT
184
- case 'J' => LONG
185
- case 'D' => DOUBLE
186
- case '[' => ArrayBType (bTypeForDescriptorOrInternalNameFromClassfile(desc.substring(1 )))
187
- case 'L' if desc.last == ';' => classBTypeFromParsedClassfile(desc.substring(1 , desc.length - 1 ))
188
- case _ => classBTypeFromParsedClassfile(desc)
189
- }
190
-
191
- /**
192
- * Parse the classfile for `internalName` and construct the [[ClassBType ]]. If the classfile cannot
193
- * be found in the `byteCodeRepository`, the `info` of the resulting ClassBType is undefined.
194
- */
195
- def classBTypeFromParsedClassfile (internalName : InternalName ): ClassBType = {
196
- cachedClassBType(internalName).getOrElse({
197
- val res = ClassBType (internalName)(classBTypeCacheFromClassfile)
198
- byteCodeRepository.classNode(internalName) match {
199
- case Left (msg) => res.info = Left (NoClassBTypeInfoMissingBytecode (msg)); res
200
- case Right (c) => setClassInfoFromClassNode(c, res)
201
- }
202
- })
203
- }
204
-
205
- /**
206
- * Construct the [[ClassBType ]] for a parsed classfile.
207
- */
208
- def classBTypeFromClassNode (classNode : ClassNode ): ClassBType = {
209
- cachedClassBType(classNode.name).getOrElse({
210
- setClassInfoFromClassNode(classNode, ClassBType (classNode.name)(classBTypeCacheFromClassfile))
211
- })
212
- }
213
-
214
- private def setClassInfoFromClassNode (classNode : ClassNode , classBType : ClassBType ): ClassBType = {
215
- val superClass = classNode.superName match {
216
- case null =>
217
- assert(classNode.name == ObjectRef .internalName, s " class with missing super type: ${classNode.name}" )
218
- None
219
- case superName =>
220
- Some (classBTypeFromParsedClassfile(superName))
221
- }
222
-
223
- val flags = classNode.access
224
-
225
- /**
226
- * Find all nested classes of classNode. The innerClasses attribute contains all nested classes
227
- * that are declared inside classNode or used in the bytecode of classNode. So some of them are
228
- * nested in some other class than classNode, and we need to filter them.
229
- *
230
- * For member classes, innerClassNode.outerName is defined, so we compare that to classNode.name.
231
- *
232
- * For local and anonymous classes, innerClassNode.outerName is null. Such classes are required
233
- * to have an EnclosingMethod attribute declaring the outer class. So we keep those local and
234
- * anonymous classes whose outerClass is classNode.name.
235
- */
236
- def nestedInCurrentClass (innerClassNode : InnerClassNode ): Boolean = {
237
- (innerClassNode.outerName != null && innerClassNode.outerName == classNode.name) ||
238
- (innerClassNode.outerName == null && {
239
- val classNodeForInnerClass = byteCodeRepository.classNode(innerClassNode.name).ge
F438
t // TODO: don't get here, but set the info to Left at the end
240
- classNodeForInnerClass.outerClass == classNode.name
241
- })
242
- }
243
-
244
- def nestedClasses : List [ClassBType ] = classNode.innerClasses.asScala.collect({
245
- case i if nestedInCurrentClass(i) => classBTypeFromParsedClassfile(i.name)
246
- })(collection.breakOut)
247
-
248
- // if classNode is a nested class, it has an innerClass attribute for itself. in this
249
- // case we build the NestedInfo.
250
- def nestedInfo = classNode.innerClasses.asScala.find(_.name == classNode.name) map {
251
- case innerEntry =>
252
- val enclosingClass =
253
- if (innerEntry.outerName != null ) {
254
- // if classNode is a member class, the outerName is non-null
255
- classBTypeFromParsedClassfile(innerEntry.outerName)
256
- } else {
257
- // for anonymous or local classes, the outerName is null, but the enclosing class is
258
- // stored in the EnclosingMethod attribute (which ASM encodes in classNode.outerClass).
259
- classBTypeFromParsedClassfile(classNode.outerClass)
260
- }
261
- val staticFlag = (innerEntry.access & Opcodes .ACC_STATIC ) != 0
262
- NestedInfo (enclosingClass, Option (innerEntry.outerName), Option (innerEntry.innerName), staticFlag)
263
- }
264
-
265
- val inlineInfo = inlineInfoFromClassfile(classNode)
266
-
267
- val interfaces : List [ClassBType ] = classNode.interfaces.asScala.map(classBTypeFromParsedClassfile)(collection.breakOut)
268
-
269
- classBType.info = Right (ClassInfo (superClass, interfaces, flags, Lazy (nestedClasses), Lazy (nestedInfo), inlineInfo))
270
- classBType
271
- }
272
-
273
- /**
274
- * Build the InlineInfo for a class. For Scala classes, the information is stored in the
275
- * ScalaInlineInfo attribute. If the attribute is missing, the InlineInfo is built using the
276
- * metadata available in the classfile (ACC_FINAL flags, etc).
277
- */
278
- def inlineInfoFromClassfile (classNode : ClassNode ): InlineInfo = {
279
- def fromClassfileAttribute : Option [InlineInfo ] = {
280
- if (classNode.attrs == null ) None
281
- else classNode.attrs.asScala.collectFirst{ case a : InlineInfoAttribute => a.inlineInfo}
282
- }
283
-
284
- def fromClassfileWithoutAttribute = {
285
- val warning = {
286
- val isScala = classNode.attrs != null && classNode.attrs.asScala.exists(a => a.`type` == BTypes .ScalaAttributeName || a.`type` == BTypes .ScalaSigAttributeName )
287
- if (isScala) Some (NoInlineInfoAttribute (classNode.name))
288
- else None
289
- }
290
- // when building MethodInlineInfos for the members of a ClassSymbol, we exclude those methods
291
- // in scalaPrimitives. This is necessary because some of them have non-erased types, which would
292
- // require special handling. Excluding is OK because they are never inlined.
293
- // Here we are parsing from a classfile and we don't need to do anything special. Many of these
294
- // primitives don't even exist, for example Any.isInstanceOf.
295
- val methodInfos : Map [String ,MethodInlineInfo ] = classNode.methods.asScala.map(methodNode => {
296
- val info = MethodInlineInfo (
297
- effectivelyFinal = BytecodeUtils .isFinalMethod(methodNode),
298
- annotatedInline = false ,
299
- annotatedNoInline = false )
300
- (methodNode.name + methodNode.desc, info)
301
- })(scala.collection.breakOut)
302
- InlineInfo (
303
- isEffectivelyFinal = BytecodeUtils .isFinalClass(classNode),
304
- sam = inlinerHeuristics.javaSam(classNode.name),
305
- methodInfos = methodInfos,
306
- warning)
307
- }
308
-
309
- // The InlineInfo is built from the classfile (not from the symbol) for all classes that are NOT
310
- // being compiled. For those classes, the info is only needed if the inliner is enabled, otherwise
311
- // we can save the memory.
312
- if (! compilerSettings.optInlinerEnabled) BTypes .EmptyInlineInfo
313
- else fromClassfileAttribute getOrElse fromClassfileWithoutAttribute
314
- }
315
-
316
132
/**
317
133
* A BType is either a primitive type, a ClassBType, an ArrayBType of one of these, or a MethodType
318
134
* referring to BTypes.
@@ -1110,7 +926,7 @@ abstract class BTypes {
1110
926
1111
927
def onForce (f : T => Unit ): Unit = {
1112
928
if (value != null ) f(value)
1113
- else frontendLock. synchronized {
929
+ else frontendSynch {
1114
930
if (value != null ) f(value)
1115
931
else {
1116
932
val prev = function
@@ -1124,7 +940,7 @@ abstract class BTypes {
1124
940
1125
941
def force : T = {
1126
942
if (value != null ) value
1127
- else frontendLock. synchronized {
943
+ else frontendSynch {
1128
944
if (value == null ) {
1129
945
function()
1130
946
function = null
0 commit comments