Add CompilerPhase and corresponding compiler keys

This commit is contained in:
Georgy Bronnikov
2018-10-16 17:55:16 +03:00
parent ecba313223
commit 32640750ee
35 changed files with 642 additions and 80 deletions
@@ -0,0 +1,149 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
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
interface CompilerPhase<in Context : BackendContext, Data> {
val name: String
val description: String
val prerequisite: Set<CompilerPhase<*, *>>
get() = emptySet()
fun invoke(context: Context, input: Data): Data
}
private typealias AnyPhase = CompilerPhase<*, *>
class CompilerPhases(private val phaseList: List<AnyPhase>, config: CompilerConfiguration) {
val phases = phaseList.associate { it.name to it }
val enabled = computeEnabled(config)
val verbose = phaseSetFromConfiguration(config, CommonConfigurationKeys.VERBOSE_PHASES)
val toDumpStateBefore: Set<AnyPhase>
val toDumpStateAfter: 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
}
}
fun known(name: String): String {
if (phases[name] == null) {
error("Unknown phase: $name. Use -Xlist-phases to see the list of phases.")
}
return name
}
fun list() {
phaseList.forEach { phase ->
val enabled = if (phase in enabled) "(Enabled)" else ""
val verbose = if (phase in verbose) "(Verbose)" else ""
println(String.format("%1$-30s %2$-50s %3$-10s", "${phase.name}:", phase.description, "$enabled $verbose"))
}
}
private fun computeEnabled(config: CompilerConfiguration) =
with(CommonConfigurationKeys) {
val disabledPhases = phaseSetFromConfiguration(config, DISABLED_PHASES)
phases.values.toSet() - disabledPhases
}
private fun phaseSetFromConfiguration(config: CompilerConfiguration, key: CompilerConfigurationKey<Set<String>>): Set<AnyPhase> {
val phaseNames = config.get(key) ?: emptySet()
if ("ALL" in phaseNames) return phases.values.toSet()
return phaseNames.map { phases[it]!! }.toSet()
}
}
interface PhaseRunner<Context : BackendContext, Data> {
fun reportBefore(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)
}
/* 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,
val data: Data,
private val phaseRunner: PhaseRunner<Context, Data>,
val parent: CompilerPhaseManager<Context, *>? = null
) {
val depth: Int = parent?.depth?.inc() ?: 0
private val previousPhases = mutableSetOf<CompilerPhase<Context, Data>>()
fun <NewData> createChild(
newData: NewData,
newPhaseRunner: PhaseRunner<Context, NewData>
) = CompilerPhaseManager(
context, phases, newData, newPhaseRunner, parent = this
)
fun createChild() = createChild(data, phaseRunner)
private fun checkPrerequisite(phase: CompilerPhase<*, *>): Boolean =
previousPhases.contains(phase) || parent?.checkPrerequisite(phase) == true
fun phase(phase: CompilerPhase<Context, Data>, context: Context, source: Data): Data {
if (phase !in phases.enabled) return source
phase.prerequisite.forEach {
if (!checkPrerequisite(it))
throw Error("$phase requires $it")
}
previousPhases.add(phase)
phaseRunner.reportBefore(phase, depth, context, source)
val result = phaseRunner.runBody(phase, context, source)
phaseRunner.reportAfter(phase, depth, context, result)
return result
}
}
fun <Context : BackendContext> makePhase(
loweringConstructor: (Context) -> FileLoweringPass,
description: String,
name: String,
prerequisite: Set<CompilerPhase<*, *>> = emptySet()
) = object : CompilerPhase<Context, IrFile> {
override val name = name
override val description = description
override val prerequisite = prerequisite
override fun invoke(context: Context, input: IrFile): IrFile {
loweringConstructor(context).lower(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
}
@@ -30,20 +30,28 @@ interface FileLoweringPass {
fun lower(irFile: IrFile)
}
interface ClassLoweringPass {
interface ClassLoweringPass : FileLoweringPass {
fun lower(irClass: IrClass)
override fun lower(irFile: IrFile) = runOnFilePostfix(irFile)
}
interface DeclarationContainerLoweringPass {
interface DeclarationContainerLoweringPass : FileLoweringPass {
fun lower(irDeclarationContainer: IrDeclarationContainer)
override fun lower(irFile: IrFile) = runOnFilePostfix(irFile)
}
interface FunctionLoweringPass {
interface FunctionLoweringPass : FileLoweringPass {
fun lower(irFunction: IrFunction)
override fun lower(irFile: IrFile) = runOnFilePostfix(irFile)
}
interface BodyLoweringPass {
interface BodyLoweringPass : FileLoweringPass {
fun lower(irBody: IrBody)
override fun lower(irFile: IrFile) = runOnFilePostfix(irFile)
}
fun ClassLoweringPass.runOnFilePostfix(irFile: IrFile) {
@@ -67,7 +75,7 @@ fun DeclarationContainerLoweringPass.asClassLoweringPass() = object : ClassLower
fun DeclarationContainerLoweringPass.runOnFilePostfix(irFile: IrFile) {
this.asClassLoweringPass().runOnFilePostfix(irFile)
this.lower(irFile)
this.lower(irFile as IrDeclarationContainer)
}
fun BodyLoweringPass.runOnFilePostfix(irFile: IrFile) {
@@ -5,10 +5,7 @@
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
@@ -39,6 +36,16 @@ 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) :
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.CompilerPhase
import org.jetbrains.kotlin.backend.common.ir.SetDeclarationsParentVisitor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
@@ -29,6 +30,17 @@ 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(
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.makePhase
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
@@ -26,6 +27,12 @@ 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()
@@ -167,6 +174,12 @@ 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() {
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.makePhase
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -37,6 +38,12 @@ 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))
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.CompilerPhase
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -33,6 +34,16 @@ import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
fun makeLateinitPhase(generateParameterNameInAssertion: Boolean) = object : CompilerPhase<CommonBackendContext, IrFile> {
override val name = "Lateinit"
override val description = "Insert checks for lateinit field references"
override fun invoke(context: CommonBackendContext, input: IrFile): IrFile {
LateinitLowering(context, generateParameterNameInAssertion).lower(input)
return input
}
}
class LateinitLowering(
val context: CommonBackendContext,
private val generateParameterNameInAssertion: Boolean = false
@@ -130,4 +141,4 @@ class LateinitLowering(
}
private val throwErrorFunction = context.ir.symbols.ThrowUninitializedPropertyAccessException.owner
}
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.common.makePhase
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
@@ -35,9 +36,24 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
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()
@@ -55,7 +71,18 @@ val IrDeclaration.parents: Sequence<IrDeclarationParent>
object BOUND_VALUE_PARAMETER: IrDeclarationOriginImpl("BOUND_VALUE_PARAMETER")
class LocalDeclarationsLowering(
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(
val context: BackendContext,
val localNameProvider: LocalNameProvider = LocalNameProvider.DEFAULT,
val loweredConstructorVisibility: Visibility = Visibilities.PRIVATE,
@@ -773,4 +800,4 @@ class LocalDeclarationsLowering(
}
}
}
}
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.makePhase
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
@@ -16,7 +18,15 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
class PropertiesLowering : IrElementTransformerVoid(), FileLoweringPass {
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()
override fun lower(irFile: IrFile) {
irFile.accept(this, null)
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.makePhase
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
@@ -33,6 +34,12 @@ 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,6 +27,12 @@ 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.
*