Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions compiler/src/dotty/tools/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ class GenBCode extends Phase { self =>
_optimizerUtils.nn
}

private var _frontendAccess: PostProcessorFrontendAccess | Null = null
def frontendAccess(using Context): PostProcessorFrontendAccess = {
if _frontendAccess eq null then
_frontendAccess = PostProcessorFrontendAccess(ctx)
_frontendAccess.nn
}

private var _primitives: ScalaPrimitives | Null = null
def primitives(using Context): ScalaPrimitives = {
if _primitives eq null then
Expand Down Expand Up @@ -98,15 +91,15 @@ class GenBCode extends Phase { self =>
private var _callGraph: CallGraph | Null = null
def callGraph(using Context): CallGraph = {
if _callGraph eq null then
_callGraph = new CallGraph(frontendAccess, byteCodeRepository, bTypesFromClassfile)
_callGraph = new CallGraph(byteCodeRepository, bTypesFromClassfile)
_callGraph.nn
}

private var _postProcessor: PostProcessor | Null = null
def postProcessor(using Context): PostProcessor = {
if _postProcessor eq null then
if ctx.settings.optInlineEnabled || ctx.settings.optClosureInvocations then
_postProcessor = new PostProcessorWithOptimizations(frontendAccess, byteCodeRepository, bTypesFromClassfile, callGraph, optimizerUtils, bTypeLoader, optimizerKnownBTypes)
_postProcessor = new PostProcessorWithOptimizations(byteCodeRepository, bTypesFromClassfile, callGraph, optimizerUtils, bTypeLoader, optimizerKnownBTypes)
else
_postProcessor = new PostProcessor(bTypeLoader, knownBTypes)
_postProcessor.nn
Expand Down
19 changes: 6 additions & 13 deletions compiler/src/dotty/tools/backend/jvm/PostProcessor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import scala.util.chaining.scalaUtilChainingOps
*/
class PostProcessor(bTypeLoader: BTypeLoader, bTypes: KnownBTypes)(using Context) {

given FileWriters.ReadOnlyContext = FileWriters.ReadOnlyContext.eager
private val classfileWriter: FileWriters.ClassfileWriter = {
val dumpClassesPath =
ctx.settings.Xdumpclasses.valueSetByUser
Expand Down Expand Up @@ -243,8 +242,6 @@ class PostProcessor(bTypeLoader: BTypeLoader, bTypes: KnownBTypes)(using Context
* It's what ASM needs to know in order to compute stack map frames, http://asm.ow2.org/doc/developer-guide.html#controlflow
*/
private final class ClassWriterWithBTypeLub(flags: Int) extends ClassWriter(flags) {
private val objectRef = bTypeLoader.classBTypeFromSymbol(defn.ObjectClass)

/**
* This method is used by asm when computing stack map frames.
*/
Expand All @@ -253,22 +250,21 @@ class PostProcessor(bTypeLoader: BTypeLoader, bTypes: KnownBTypes)(using Context
// i.e., have been loaded either from symbols or from class files.
val a = bTypeLoader.previouslyConstructedClassBType(inameA).get
val b = bTypeLoader.previouslyConstructedClassBType(inameB).get
val lub = a.jvmWiseLUB(b, objectRef)
val lub = a.jvmWiseLUB(b, bTypes.ObjectRef)
val lubName = lub.internalName
assert(lubName != "scala/Any")
lubName // ASM caches the answer during the lifetime of a ClassWriter. We outlive that. Not sure whether caching on our side would improve things.
}
}
}

final class PostProcessorWithOptimizations(frontendAccess: PostProcessorFrontendAccess,
byteCodeRepository: BCodeRepository, bTypesFromClassfile: BTypesFromClassfile,
final class PostProcessorWithOptimizations(byteCodeRepository: BCodeRepository, bTypesFromClassfile: BTypesFromClassfile,
callGraph: CallGraph, optimizerUtils: OptimizerUtils,
bTypeLoader: BTypeLoader, bTypes: OptimizerKnownBTypes)(using Context) extends PostProcessor(bTypeLoader, bTypes) {
private val optSettings = new OptimizerSettings()
private val closureOptimizer = new ClosureOptimizer(frontendAccess, optimizerUtils, byteCodeRepository, callGraph, bTypes, bTypesFromClassfile, optSettings)
private val heuristics = new InlinerHeuristics(frontendAccess, optimizerUtils, byteCodeRepository, callGraph, bTypes, optSettings)
private val inliner = new Inliner(frontendAccess, optimizerUtils, callGraph, bTypeLoader, bTypesFromClassfile, byteCodeRepository, heuristics, closureOptimizer, optSettings)
private val closureOptimizer = new ClosureOptimizer(optimizerUtils, byteCodeRepository, callGraph, bTypes, bTypesFromClassfile, optSettings)
private val heuristics = new InlinerHeuristics(optimizerUtils, byteCodeRepository, callGraph, bTypes, optSettings)
private val inliner = new Inliner(optimizerUtils, callGraph, bTypeLoader, bTypesFromClassfile, byteCodeRepository, heuristics, closureOptimizer, optSettings)
private val localOpt = new LocalOpt(optimizerUtils, callGraph, inliner, bTypes, bTypesFromClassfile, optSettings)

override def runGlobalOptimizations(generatedUnits: Iterable[GeneratedCompilationUnit]): Unit = {
Expand All @@ -283,10 +279,7 @@ final class PostProcessorWithOptimizations(frontendAccess: PostProcessorFrontend
if !c.isArtifact // skip call graph for mirror / bean: we don't inline into them, and they are not referenced from other classes
do
callGraph.addClass(c.classNode)
if ctx.settings.optInlineEnabled then
inliner.runInlinerAndClosureOptimizer()
else // we're only called if either optInlineEnabled or ctx.settings.optClosureInvocations
closureOptimizer.rewriteClosureApplyInvocations(None, scala.collection.mutable.Map.empty)
inliner.runInlinerAndClosureOptimizer(i => report.optimizerWarning(i.msg, i.site, i.pos))
}

protected override def runLocalOptimizations(classNode: ClassNode): Unit =
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,14 @@ class BTypesFromClassfile(byteCodeRepository: BCodeRepository, bTypeLoader: BTyp
}

def loadInlineInfoFor(name: InternalName): InlineInfo =
byteCodeRepository.classNode(name) match {
if OptimizerUtils.isSCoverage(name) then InlineInfo.empty
else byteCodeRepository.classNode(name) match {
case Right(classNode, moduleNode) =>
inlineInfoFromClassfile(classNode, moduleNode)
case Left(missingClass) =>
InlineInfo.empty.copy(warning = Some(ClassNotFoundWhenBuildingInlineInfoFromSymbol(missingClass)))
}

/**
* Build the InlineInfo for a class. For Scala classes, the information is stored in the
* ScalaInlineInfo attribute. If the attribute is missing, the InlineInfo is built using the
Expand Down
23 changes: 12 additions & 11 deletions compiler/src/dotty/tools/backend/jvm/opt/CallGraph.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ import BCodeUtils.*
import dotty.tools.dotc.util.{NoSourcePosition, SourcePosition}
import dotty.tools.dotc.ast.Positioned

class CallGraph(frontendAccess: PostProcessorFrontendAccess,
byteCodeRepository: BCodeRepository, bTypesFromClassfile: BTypesFromClassfile) {
class CallGraph(byteCodeRepository: BCodeRepository, bTypesFromClassfile: BTypesFromClassfile) {

/**
* The call graph contains the callsites in the program being compiled.
Expand Down Expand Up @@ -175,16 +174,15 @@ class CallGraph(frontendAccess: PostProcessorFrontendAccess,
declarationClassBType <- bTypesFromClassfile.classBTypeFromClassNode(declarationClassNode, declarationModuleNode)
} yield {
val info = analyzeCallsite(method, declarationClassBType, call, paramTps, calleeSourceFilePath, definingClass)
import info._
Callee(
callee = method,
calleeDeclarationClass = declarationClassBType,
isStaticallyResolved = isStaticallyResolved,
sourceFilePath = sourceFilePath,
annotatedInline = annotatedInline,
annotatedNoInline = annotatedNoInline,
isStaticallyResolved = info.isStaticallyResolved,
sourceFilePath = info.sourceFilePath,
annotatedInline = info.annotatedInline,
annotatedNoInline = info.annotatedNoInline,
samParamTypes = info.samParamTypes,
calleeInfoWarning = warning)
calleeInfoWarning = info.warning)
}
}

Expand Down Expand Up @@ -418,9 +416,12 @@ class CallGraph(frontendAccess: PostProcessorFrontendAccess,
warning = warning)

case None =>
val warning = MethodInlineInfoMissing(calleeDeclarationClassBType.internalName, calleeMethodNode.name, calleeMethodNode.desc,
calleeDeclarationClassBType.info.inlineInfo.warning)
CallsiteInfo(warning = Some(warning))
if OptimizerUtils.isSCoverage(calleeDeclarationClassBType.internalName) then
CallsiteInfo(warning = None)
else
val warning = MethodInlineInfoMissing(calleeDeclarationClassBType.internalName, calleeMethodNode.name, calleeMethodNode.desc,
calleeDeclarationClassBType.info.inlineInfo.warning)
CallsiteInfo(warning = Some(warning))
}
}
}
Expand Down
17 changes: 8 additions & 9 deletions compiler/src/dotty/tools/backend/jvm/opt/ClosureOptimizer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ import scala.jdk.CollectionConverters.*
import scala.tools.asm.Opcodes.*
import scala.tools.asm.Type
import scala.tools.asm.tree.*
import dotty.tools.dotc.core.Decorators.em
import dotty.tools.dotc.util.NoSourcePosition
import dotty.tools.backend.jvm.BTypes.InternalName
import dotty.tools.backend.jvm.analysis.{AnalysisUtils, AsmAnalyzer, ProdConsAnalyzer}
import BCodeUtils.*

class ClosureOptimizer(ppa: PostProcessorFrontendAccess, optimizerUtils: OptimizerUtils,
class ClosureOptimizer(optimizerUtils: OptimizerUtils,
byteCodeRepository: BCodeRepository, callGraph: CallGraph,
ts: OptimizerKnownBTypes, bTypesFromClassfile: BTypesFromClassfile,
settings: OptimizerSettings) {
Expand Down Expand Up @@ -85,7 +84,7 @@ class ClosureOptimizer(ppa: PostProcessorFrontendAccess, optimizerUtils: Optimiz
* instantiations.
* @return The changed methods. The order of the resulting sequence is deterministic.
*/
def rewriteClosureApplyInvocations(methods: Option[Iterable[MethodNode]], inlinerState: mutable.Map[MethodNode, MethodInlinerState]): mutable.LinkedHashSet[MethodNode] = {
def rewriteClosureApplyInvocations(methods: Option[Iterable[MethodNode]], inlinerState: mutable.Map[MethodNode, MethodInlinerState], issueSink: OptimizerIssue => Unit): mutable.LinkedHashSet[MethodNode] = {

// sort all closure invocations to rewrite to ensure bytecode stability
given Ordering[ClosureInstantiation] = closureInitOrdering
Expand Down Expand Up @@ -117,7 +116,7 @@ class ClosureOptimizer(ppa: PostProcessorFrontendAccess, optimizerUtils: Optimiz

for (init <- closureInits.valuesIterator) closureCallsites(init, prodCons) foreach {
case Left(warning) =>
ppa.optimizerWarning(em"${warning.toString}", OptimizerUtils.siteString(ownerClass, method.name), warning.pos)
issueSink(OptimizerIssue(warning.toString, OptimizerUtils.siteString(ownerClass, method.name), warning.pos))

case Right((invocation, stackHeight)) =>
addRewrite(init, invocation, stackHeight)
Expand Down Expand Up @@ -518,11 +517,11 @@ class ClosureOptimizer(ppa: PostProcessorFrontendAccess, optimizerUtils: Optimiz
/**
* A list of local variables. Each local stores information about its type, see class [[Local]].
*/
case class LocalsList(locals: List[Local]) {
private case class LocalsList(locals: List[Local]) {
val size = locals.iterator.map(_.size).sum
}

object LocalsList {
private object LocalsList {
/**
* A list of local variables starting at `firstLocal` that can hold values of the types in the
* `types` parameter.
Expand Down Expand Up @@ -552,7 +551,7 @@ class ClosureOptimizer(ppa: PostProcessorFrontendAccess, optimizerUtils: Optimiz
* The xLOAD / xSTORE opcodes are in the following sequence: I, L, F, D, A, so the offset for
* a local variable holding a reference (`A`) is 4. See also method `getOpcode` in [[scala.tools.asm.Type]].
*/
case class Local(local: Int, opcodeOffset: Int) {
private case class Local(local: Int, opcodeOffset: Int) {
def size = if (loadOpcode == LLOAD || loadOpcode == DLOAD) 2 else 1

def loadOpcode = ILOAD + opcodeOffset
Expand All @@ -561,6 +560,6 @@ class ClosureOptimizer(ppa: PostProcessorFrontendAccess, optimizerUtils: Optimiz
}

object ClosureOptimizer {
val primitives = "BSIJCFDZV"
val specializationSuffix = s"(\\$$mc[$primitives]+\\$$sp)".r
private val primitives = "BSIJCFDZV"
private val specializationSuffix = s"(\\$$mc[$primitives]+\\$$sp)".r
}
Loading
Loading