Refactored Common & JVM IR Phaser
This commit is contained in:
+109
-29
@@ -8,7 +8,9 @@ package org.jetbrains.kotlin.backend.common
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
interface CompilerPhase<in Context : BackendContext, Data> {
|
||||
val name: String
|
||||
@@ -31,13 +33,21 @@ class CompilerPhases(private val phaseList: List<AnyPhase>, config: CompilerConf
|
||||
val toDumpStateBefore: Set<AnyPhase>
|
||||
val toDumpStateAfter: Set<AnyPhase>
|
||||
|
||||
val toValidateStateBefore: Set<AnyPhase>
|
||||
val toValidateStateAfter: Set<AnyPhase>
|
||||
|
||||
init {
|
||||
with(CommonConfigurationKeys) {
|
||||
val beforeSet = phaseSetFromConfiguration(config, PHASES_TO_DUMP_STATE_BEFORE)
|
||||
val afterSet = phaseSetFromConfiguration(config, PHASES_TO_DUMP_STATE_AFTER)
|
||||
val bothSet = phaseSetFromConfiguration(config, PHASES_TO_DUMP_STATE)
|
||||
toDumpStateBefore = beforeSet + bothSet
|
||||
toDumpStateAfter = afterSet + bothSet
|
||||
val beforeDumpSet = phaseSetFromConfiguration(config, PHASES_TO_DUMP_STATE_BEFORE)
|
||||
val afterDumpSet = phaseSetFromConfiguration(config, PHASES_TO_DUMP_STATE_AFTER)
|
||||
val bothDumpSet = phaseSetFromConfiguration(config, PHASES_TO_DUMP_STATE)
|
||||
toDumpStateBefore = beforeDumpSet + bothDumpSet
|
||||
toDumpStateAfter = afterDumpSet + bothDumpSet
|
||||
val beforeValidateSet = phaseSetFromConfiguration(config, PHASES_TO_VALIDATE_BEFORE)
|
||||
val afterValidateSet = phaseSetFromConfiguration(config, PHASES_TO_VALIDATE_AFTER)
|
||||
val bothValidateSet = phaseSetFromConfiguration(config, PHASES_TO_VALIDATE)
|
||||
toValidateStateBefore = beforeValidateSet + bothValidateSet
|
||||
toValidateStateAfter = afterValidateSet + bothValidateSet
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,13 +80,95 @@ class CompilerPhases(private val phaseList: List<AnyPhase>, config: CompilerConf
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface PhaseRunner<Context : BackendContext, Data> {
|
||||
fun reportBefore(phase: CompilerPhase<Context, Data>, depth: Int, context: Context, data: Data)
|
||||
fun runBefore(phase: CompilerPhase<Context, Data>, depth: Int, context: Context, data: Data)
|
||||
fun runBody(phase: CompilerPhase<Context, Data>, context: Context, source: Data): Data
|
||||
fun reportAfter(phase: CompilerPhase<Context, Data>, depth: Int, context: Context, data: Data)
|
||||
fun runAfter(phase: CompilerPhase<Context, Data>, depth: Int, context: Context, data: Data)
|
||||
}
|
||||
|
||||
abstract class DefaultIrPhaseRunner<Context : CommonBackendContext, Data : IrElement>(private val validator: (data: Data, context: Context) -> Unit = { _, _ -> }) :
|
||||
PhaseRunner<Context, Data> {
|
||||
|
||||
enum class BeforeOrAfter { BEFORE, AFTER }
|
||||
|
||||
abstract val startPhaseMarker: CompilerPhase<Context, Data>
|
||||
abstract val endPhaseMarker: CompilerPhase<Context, Data>
|
||||
|
||||
private var inVerbosePhase = false
|
||||
|
||||
final override fun runBefore(phase: CompilerPhase<Context, Data>, depth: Int, context: Context, data: Data) {
|
||||
checkAndRun(phase, phases(context).toDumpStateBefore) { dumpElement(data, phase, context, BeforeOrAfter.BEFORE) }
|
||||
checkAndRun(phase, phases(context).toValidateStateBefore) { validator(data, context) }
|
||||
}
|
||||
|
||||
final override fun runBody(phase: CompilerPhase<Context, Data>, context: Context, source: Data): Data {
|
||||
val runner = when {
|
||||
phase === startPhaseMarker -> ::justRun
|
||||
phase === endPhaseMarker -> ::justRun
|
||||
needProfiling(context) -> ::runAndProfile
|
||||
else -> ::justRun
|
||||
}
|
||||
|
||||
inVerbosePhase = phase in phases(context).verbose
|
||||
|
||||
val result = runner(phase, context, source)
|
||||
|
||||
inVerbosePhase = false
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
final override fun runAfter(phase: CompilerPhase<Context, Data>, depth: Int, context: Context, data: Data) {
|
||||
checkAndRun(phase, phases(context).toDumpStateAfter) { dumpElement(data, phase, context, BeforeOrAfter.AFTER) }
|
||||
checkAndRun(phase, phases(context).toValidateStateAfter) { validator(data, context) }
|
||||
}
|
||||
|
||||
open fun separator(title: String) = println("\n\n--- $title ----------------------\n")
|
||||
|
||||
protected abstract fun phases(context: Context): CompilerPhases
|
||||
protected abstract fun elementName(input: Data): String
|
||||
protected abstract fun configuration(context: Context): CompilerConfiguration
|
||||
|
||||
private fun needProfiling(context: Context) = configuration(context).getBoolean(CommonConfigurationKeys.PROFILE_PHASES)
|
||||
|
||||
private fun shouldBeDumped(context: Context, input: Data) =
|
||||
elementName(input) !in configuration(context).get(CommonConfigurationKeys.EXCLUDED_ELEMENTS_FROM_DUMPING, emptySet())
|
||||
|
||||
private fun checkAndRun(phase: CompilerPhase<Context, Data>, set: Set<AnyPhase>, block: () -> Unit) {
|
||||
if (phase in set) block()
|
||||
}
|
||||
|
||||
private fun dumpElement(input: Data, phase: CompilerPhase<Context, Data>, context: Context, beforeOrAfter: BeforeOrAfter) {
|
||||
// Exclude nonsensical combinations
|
||||
if (phase === startPhaseMarker && beforeOrAfter == BeforeOrAfter.AFTER) return
|
||||
if (phase === endPhaseMarker && beforeOrAfter == BeforeOrAfter.BEFORE) return
|
||||
|
||||
if (!shouldBeDumped(context, input)) return
|
||||
|
||||
val title = when (phase) {
|
||||
startPhaseMarker -> "IR for ${elementName(input)} at the start of lowering process"
|
||||
endPhaseMarker -> "IR for ${elementName(input)} at the end of lowering process"
|
||||
else -> {
|
||||
val beforeOrAfterStr = beforeOrAfter.name.toLowerCase()
|
||||
"IR for ${elementName(input)} $beforeOrAfterStr ${phase.description}"
|
||||
}
|
||||
}
|
||||
separator(title)
|
||||
println(input.dump())
|
||||
}
|
||||
|
||||
private fun runAndProfile(phase: CompilerPhase<Context, Data>, context: Context, source: Data): Data {
|
||||
var result: Data = source
|
||||
val msec = measureTimeMillis { result = phase.invoke(context, source) }
|
||||
println("${phase.description}: $msec msec")
|
||||
return result
|
||||
}
|
||||
|
||||
private fun justRun(phase: CompilerPhase<Context, Data>, context: Context, source: Data) =
|
||||
phase.invoke(context, source)
|
||||
}
|
||||
|
||||
/* We assume that `element` is being modified by each phase, retaining its identity in the process. */
|
||||
class CompilerPhaseManager<Context : BackendContext, Data>(
|
||||
val context: Context,
|
||||
val phases: CompilerPhases,
|
||||
@@ -111,39 +203,27 @@ class CompilerPhaseManager<Context : BackendContext, Data>(
|
||||
|
||||
previousPhases.add(phase)
|
||||
|
||||
phaseRunner.reportBefore(phase, depth, context, source)
|
||||
phaseRunner.runBefore(phase, depth, context, source)
|
||||
val result = phaseRunner.runBody(phase, context, source)
|
||||
phaseRunner.reportAfter(phase, depth, context, result)
|
||||
phaseRunner.runAfter(phase, depth, context, result)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
fun <Context : BackendContext> makePhase(
|
||||
loweringConstructor: (Context) -> FileLoweringPass,
|
||||
fun <Context : BackendContext, Data> makePhase(
|
||||
lowering: (Context, Data) -> Unit,
|
||||
description: String,
|
||||
name: String,
|
||||
prerequisite: Set<CompilerPhase<*, *>> = emptySet()
|
||||
) = object : CompilerPhase<Context, IrFile> {
|
||||
) = object : CompilerPhase<Context, Data> {
|
||||
override val name = name
|
||||
override val description = description
|
||||
override val prerequisite = prerequisite
|
||||
|
||||
override fun invoke(context: Context, input: IrFile): IrFile {
|
||||
loweringConstructor(context).lower(input)
|
||||
override fun invoke(context: Context, input: Data): Data {
|
||||
lowering(context, input)
|
||||
return input
|
||||
}
|
||||
}
|
||||
|
||||
object IrFileStartPhase : CompilerPhase<BackendContext, IrFile> {
|
||||
override val name = "IrFileStart"
|
||||
override val description = "State at start of IrFile lowering"
|
||||
override val prerequisite = emptySet()
|
||||
override fun invoke(context: BackendContext, input: IrFile) = input
|
||||
}
|
||||
|
||||
object IrFileEndPhase : CompilerPhase<BackendContext, IrFile> {
|
||||
override val name = "IrFileEnd"
|
||||
override val description = "State at end of IrFile lowering"
|
||||
override val prerequisite = emptySet()
|
||||
override fun invoke(context: BackendContext, input: IrFile) = input
|
||||
override fun toString() = "Compiler Phase @$name"
|
||||
}
|
||||
-10
@@ -37,16 +37,6 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
fun makeDefaultArgumentStubPhase(skipInlineMethods: Boolean) = object : CompilerPhase<CommonBackendContext, IrFile> {
|
||||
override val name = "DefaultArgumentsStubGenerator"
|
||||
override val description = "Generate synthetic stubs for functions with default parameter values"
|
||||
|
||||
override fun invoke(context: CommonBackendContext, input: IrFile): IrFile {
|
||||
DefaultArgumentStubGenerator(context, skipInlineMethods).lower(input)
|
||||
return input
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fix expect/actual default parameters
|
||||
|
||||
open class DefaultArgumentStubGenerator constructor(val context: CommonBackendContext, private val skipInlineMethods: Boolean = true) :
|
||||
|
||||
-11
@@ -34,17 +34,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
|
||||
fun makeInitializersPhase(declarationOrigin: IrDeclarationOrigin, clinitNeeded: Boolean) = object :
|
||||
CompilerPhase<CommonBackendContext, IrFile> {
|
||||
override val name = "Initializers"
|
||||
override val description = "Handle initializer statements"
|
||||
|
||||
override fun invoke(context: CommonBackendContext, input: IrFile): IrFile {
|
||||
InitializersLowering(context, declarationOrigin, clinitNeeded).lower(input)
|
||||
return input
|
||||
}
|
||||
}
|
||||
|
||||
object SYNTHESIZED_INIT_BLOCK: IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK")
|
||||
|
||||
class InitializersLowering(
|
||||
|
||||
-12
@@ -28,12 +28,6 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import java.util.*
|
||||
|
||||
val InnerClassesPhase = makePhase(
|
||||
::InnerClassesLowering,
|
||||
name = "InnerClasses",
|
||||
description = "Move inner classes to toplevel"
|
||||
)
|
||||
|
||||
class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
InnerClassTransformer(irClass).lowerInnerClass()
|
||||
@@ -175,12 +169,6 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
||||
}
|
||||
}
|
||||
|
||||
val InnerClassConstructorCallsPhase = makePhase(
|
||||
::InnerClassConstructorCallsLowering,
|
||||
name = "InnerClassConstructorCalls",
|
||||
description = "Handle constructor calls for inner classes"
|
||||
)
|
||||
|
||||
class InnerClassConstructorCallsLowering(val context: BackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
|
||||
-6
@@ -38,12 +38,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
val KCallableNamePropertyPhase = makePhase(
|
||||
::KCallableNamePropertyLowering,
|
||||
name = "KCallableNameProperty",
|
||||
description = "Replace name references for callables with constants"
|
||||
)
|
||||
|
||||
class KCallableNamePropertyLowering(val context: BackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(KCallableNamePropertyTransformer(this))
|
||||
|
||||
+1
-26
@@ -40,20 +40,6 @@ import org.jetbrains.kotlin.name.NameUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
|
||||
import java.util.*
|
||||
|
||||
val LocalDeclarationsPhase = makePhase(
|
||||
::LocalDeclarationsLowering,
|
||||
name = "LocalDeclarations",
|
||||
description = "Move local declarations to classes",
|
||||
prerequisite = setOf(SharedVariablesPhase)
|
||||
)
|
||||
|
||||
val JvmLocalDeclarationsPhase = makePhase(
|
||||
::JvmLocalDeclarationsLowering,
|
||||
name = "JvmLocalDeclarations",
|
||||
description = "Move local declarations to classes",
|
||||
prerequisite = setOf(SharedVariablesPhase)
|
||||
)
|
||||
|
||||
interface LocalNameProvider {
|
||||
fun localName(descriptor: DeclarationDescriptor): String =
|
||||
descriptor.name.asString()
|
||||
@@ -71,18 +57,7 @@ val IrDeclaration.parents: Sequence<IrDeclarationParent>
|
||||
|
||||
object BOUND_VALUE_PARAMETER: IrDeclarationOriginImpl("BOUND_VALUE_PARAMETER")
|
||||
|
||||
class JvmLocalDeclarationsLowering(context: BackendContext) :
|
||||
LocalDeclarationsLowering(
|
||||
context,
|
||||
object : LocalNameProvider {
|
||||
override fun localName(descriptor: DeclarationDescriptor): String =
|
||||
NameUtils.sanitizeAsJavaIdentifier(super.localName(descriptor))
|
||||
},
|
||||
Visibilities.PUBLIC, //TODO properly figure out visibility
|
||||
true
|
||||
)
|
||||
|
||||
open class LocalDeclarationsLowering(
|
||||
class LocalDeclarationsLowering(
|
||||
val context: BackendContext,
|
||||
val localNameProvider: LocalNameProvider = LocalNameProvider.DEFAULT,
|
||||
val loweredConstructorVisibility: Visibility = Visibilities.PRIVATE,
|
||||
|
||||
-6
@@ -18,12 +18,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
val PropertiesPhase = makePhase(
|
||||
::PropertiesLowering,
|
||||
name = "Properties",
|
||||
description = "move fields and accessors for properties to their classes"
|
||||
)
|
||||
|
||||
class PropertiesLowering() : IrElementTransformerVoid(), FileLoweringPass {
|
||||
constructor(@Suppress("UNUSED_PARAMETER") context: BackendContext) : this()
|
||||
|
||||
|
||||
-6
@@ -34,12 +34,6 @@ import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import java.util.*
|
||||
|
||||
val SharedVariablesPhase = makePhase(
|
||||
::SharedVariablesLowering,
|
||||
name = "SharedVariables",
|
||||
description = "Transform shared variables"
|
||||
)
|
||||
|
||||
class SharedVariablesLowering(val context: BackendContext) : FunctionLoweringPass {
|
||||
override fun lower(irFunction: IrFunction) {
|
||||
SharedVariablesTransformer(irFunction).lowerSharedVariables()
|
||||
|
||||
-6
@@ -27,12 +27,6 @@ import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
val TailrecPhase = makePhase(
|
||||
::TailrecLowering,
|
||||
name = "Tailrec",
|
||||
description = "Handle tailrec calls"
|
||||
)
|
||||
|
||||
/**
|
||||
* This pass lowers tail recursion calls in `tailrec` functions.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user