Refactored Common & JVM IR Phaser

This commit is contained in:
Roman Artemev
2018-12-03 16:58:25 +03:00
committed by romanart
parent 094dc2ae45
commit 2d9d9484b3
31 changed files with 406 additions and 353 deletions
@@ -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"
}
@@ -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) :
@@ -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(
@@ -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() {
@@ -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))
@@ -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,
@@ -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()
@@ -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()
@@ -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.
*