10000 Move components from BTypes to PostProcessor · scala/scala@de9236c · GitHub
[go: up one dir, main page]

Skip to content

Commit de9236c

Browse files
committed
Move components from BTypes to PostProcessor
BTypes is the component that's shared between CodeGen and PostProcessor.
1 parent 948fb88 commit de9236c

33 files changed

+659
-482
lines changed

src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic {
2626
import definitions._
2727
import bTypes._
2828
import coreBTypes._
29+
import genBCode.postProcessor.backendUtils
2930
import BTypes.{InternalName, InlineInfo, MethodInlineInfo}
3031

3132
/**
@@ -238,9 +239,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic {
238239
try fn finally reporter = currentReporter
239240
}
240241

241-
242-
var pickledBytes = 0 // statistics
243-
244242
/*
245243
* must-single-thread
246244
*/
@@ -406,7 +404,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic {
406404
val sigBytes = ScalaSigBytes(pickle.bytes.take(pickle.writeIndex))
407405
AnnotationInfo(sigBytes.sigAnnot, Nil, (nme.bytes, sigBytes) :: Nil)
408406
}
409-
pickledBytes += pickle.writeIndex
410407
currentRun.symData -= sym
411408
currentRun.symData -= sym.companionSymbol
412409
Some(scalaAnnot)

src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
2525
import global._
2626
import bTypes._
2727
import coreBTypes._
28+
import genBCode.postProcessor.backendUtils
2829

2930
/*
3031
* There's a dedicated PlainClassBuilder for each CompilationUnit,
@@ -78,10 +79,6 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
7879

7980
def tpeTK(tree: Tree): BType = typeToBType(tree.tpe)
8081

81-
def log(msg: => AnyRef) {
82-
frontendLock synchronized { global.log(msg) }
83-
}
84-
8582
/* ---------------- helper utils for generating classes and fields ---------------- */
8683

8784
def genPlainClass(cd: ClassDef) {

src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala

Lines changed: 8 additions & 192 deletions
< 10000 /tr>
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,15 @@
66
package scala.tools.nsc
77
package backend.jvm
88

9-
import scala.annotation.switch
10-
import scala.collection.{concurrent, mutable}
119
import scala.collection.concurrent.TrieMap
10+
import scala.collection.{concurrent, mutable}
1211
import scala.reflect.internal.util.Position
1312
import scala.tools.asm
14-
import asm.Opcodes
13+
import scala.tools.asm.Opcodes
1514
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}
1716
import scala.tools.nsc.backend.jvm.BackendReporting._
18-
import scala.tools.nsc.backend.jvm.analysis.BackendUtils
1917
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
2318

2419
/**
2520
* The BTypes component defines The BType class hierarchy. A BType stores all type information
@@ -30,44 +25,15 @@ import scala.tools.nsc.settings.ScalaSettings
3025
* be queried by concurrent threads.
3126
*/
3227
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}
4130

4231
// Some core BTypes are required here, in class BType, where no Global instance is available.
4332
// The Global is only available in the subclass BTypesFromSymbols. We cannot depend on the actual
4433
// implementation (CoreBTypesProxy) here because it has members that refer to global.Symbol.
4534
val coreBTypes: CoreBTypesProxyGlobalIndependent[this.type]
4635
import coreBTypes._
4736

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-
7137
/**
7238
* Every ClassBType is cached on construction and accessible through this method.
7339
*
@@ -138,7 +104,7 @@ abstract class BTypes {
138104
def addIndyLambdaImplMethod(hostClass: InternalName, handle: Seq[asm.Handle]): Seq[asm.Handle] = {
139105
if (handle.isEmpty) Nil else {
140106
val set = indyLambdaImplMethods.getOrElseUpdate(hostClass, mutable.LinkedHashSet())
141-
if (set isEmpty) {
107+
if (set.isEmpty) {
142108
set ++= handle
143109
handle
144110
} else {
@@ -163,156 +129,6 @@ abstract class BTypes {
163129
}
164130
}
165131

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-
316132
/**
317133
* A BType is either a primitive type, a ClassBType, an ArrayBType of one of these, or a MethodType
318134
* referring to BTypes.
@@ -1110,7 +926,7 @@ abstract class BTypes {
1110926

1111927
def onForce(f: T => Unit): Unit = {
1112928
if (value != null) f(value)
1113-
else frontendLock.synchronized {
929+
else frontendSynch {
1114930
if (value != null) f(value)
1115931
else {
1116932
val prev = function
@@ -1124,7 +940,7 @@ abstract class BTypes {
1124940

1125941
def force: T = {
1126942
if (value != null) value
1127-
else frontendLock.synchronized {
943+
else frontendSynch {
1128944
if (value == null) {
1129945
function()
1130946
function = null

0 commit comments

Comments
 (0)
0