IR: simplify phaser code a little

- merge NamedCompilerPhase, SameTypeNamedPhaseWrapper,
  AbstractNamedPhaseWrapper and inherit it from SameTypeCompilerPhase
- inline some functions to simplify stacktraces
- reformat and fix inspections
This commit is contained in:
Alexander Udalov
2020-07-01 01:18:07 +02:00
parent 74ce26cdc2
commit ef58f1e72e
4 changed files with 53 additions and 103 deletions
@@ -18,8 +18,7 @@ class PhaserState<Data>(
// Copy state, forgetting the sticky postconditions (which will not be applicable to the new type)
fun <Input, Output> PhaserState<Input>.changeType() = PhaserState<Output>(alreadyDone, depth, phaseCount, mutableSetOf())
fun <R, D> PhaserState<D>.downlevel(nlevels: Int = 1, block: () -> R): R {
inline fun <R, D> PhaserState<D>.downlevel(nlevels: Int, block: () -> R): R {
depth += nlevels
val result = block()
depth -= nlevels
@@ -35,28 +34,19 @@ interface CompilerPhase<in Context : CommonBackendContext, Input, Output> {
val stickyPostconditions: Set<Checker<Output>> get() = emptySet()
}
fun <Context: CommonBackendContext, Input, Output> CompilerPhase<Context, Input, Output>.invokeToplevel(
fun <Context : CommonBackendContext, Input, Output> CompilerPhase<Context, Input, Output>.invokeToplevel(
phaseConfig: PhaseConfig,
context: Context,
input: Input
): Output = invoke(phaseConfig, PhaserState(), context, input)
interface SameTypeCompilerPhase<in Context: CommonBackendContext, Data> : CompilerPhase<Context, Data, Data>
interface SameTypeCompilerPhase<in Context : CommonBackendContext, Data> : CompilerPhase<Context, Data, Data>
// A failing checker should just throw an exception.
typealias Checker<Data> = (Data) -> Unit
interface NamedCompilerPhase<in Context : CommonBackendContext, Input, Output> : CompilerPhase<Context, Input, Output> {
val name: String
val description: String
val prerequisite: Set<AnyNamedPhase> get() = emptySet()
val preconditions: Set<Checker<Input>>
val postconditions: Set<Checker<Output>>
val actionsBefore: Set<Action<Input, Context>>
val actionsAfter: Set<Action<Output, Context>>
}
typealias AnyNamedPhase = NamedCompilerPhase<*, *>
typealias AnyNamedPhase = NamedCompilerPhase<*, *, *>
enum class BeforeOrAfter { BEFORE, AFTER }
data class ActionState(
@@ -74,25 +64,20 @@ infix operator fun <Data, Context> Action<Data, Context>.plus(other: Action<Data
other(phaseState, data, context)
}
abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Input, Output>(
override val name: String,
override val description: String,
override val prerequisite: Set<AnyNamedPhase>,
private val lower: CompilerPhase<Context, Input, Output>,
override val preconditions: Set<Checker<Input>> = emptySet(),
override val postconditions: Set<Checker<Output>> = emptySet(),
override val stickyPostconditions: Set<Checker<Output>> = emptySet(),
override val actionsBefore: Set<Action<Input, Context>> = emptySet(),
override val actionsAfter: Set<Action<Output, Context>> = emptySet(),
class NamedCompilerPhase<in Context : CommonBackendContext, Data>(
val name: String,
val description: String,
val prerequisite: Set<AnyNamedPhase>,
private val lower: CompilerPhase<Context, Data, Data>,
val preconditions: Set<Checker<Data>> = emptySet(),
val postconditions: Set<Checker<Data>> = emptySet(),
override val stickyPostconditions: Set<Checker<Data>> = emptySet(),
private val actions: Set<Action<Data, Context>> = emptySet(),
private val nlevels: Int = 0
) : NamedCompilerPhase<Context, Input, Output> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input): Output {
if (this is SameTypeCompilerPhase<*, *> &&
this !in phaseConfig.enabled
) {
@Suppress("UNCHECKED_CAST")
return input as Output
) : SameTypeCompilerPhase<Context, Data> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, input: Data): Data {
if (this !in phaseConfig.enabled) {
return input
}
assert(phaserState.alreadyDone.containsAll(prerequisite)) {
@@ -102,7 +87,13 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
context.inVerbosePhase = this in phaseConfig.verbose
runBefore(phaseConfig, phaserState, context, input)
val output = runBody(phaseConfig, phaserState, context, input)
val output = if (phaseConfig.needProfiling) {
runAndProfile(phaseConfig, phaserState, context, input)
} else {
phaserState.downlevel(nlevels) {
lower.invoke(phaseConfig, phaserState, context, input)
}
}
runAfter(phaseConfig, phaserState, context, output)
phaserState.alreadyDone.add(this)
@@ -111,41 +102,30 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
return output
}
private fun runBefore(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {
private fun runBefore(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, input: Data) {
val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.BEFORE)
for (action in actionsBefore) action(state, input, context)
for (action in actions) action(state, input, context)
if (phaseConfig.checkConditions) {
for (pre in preconditions) pre(input)
}
}
private fun runBody(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input): Output {
return if (phaseConfig.needProfiling) {
runAndProfile(phaseConfig, phaserState, context, input)
} else {
phaserState.downlevel(nlevels) {
lower.invoke(phaseConfig, phaserState, context, input)
}
}
}
private fun runAfter(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, output: Output) {
private fun runAfter(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, output: Data) {
val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.AFTER)
for (action in actionsAfter) action(state, output, context)
for (action in actions) action(state, output, context)
if (phaseConfig.checkConditions) {
for (post in postconditions) post(output)
for (post in stickyPostconditions) post(output)
if (phaseConfig.checkStickyConditions && this is SameTypeCompilerPhase<*, *>) {
@Suppress("UNCHECKED_CAST") val phaserStateO = phaserState as PhaserState<Output>
for (post in phaserStateO.stickyPostconditions) post(output)
if (phaseConfig.checkStickyConditions) {
for (post in phaserState.stickyPostconditions) post(output)
}
}
}
private fun runAndProfile(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, source: Input): Output {
var result: Output? = null
private fun runAndProfile(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, source: Data): Data {
var result: Data? = null
val msec = measureTimeMillis {
result = phaserState.downlevel(nlevels) {
lower.invoke(phaseConfig, phaserState, context, source)
@@ -156,26 +136,8 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
return result!!
}
private fun checkAndRun(set: Set<AnyNamedPhase>, block: () -> Unit) {
if (this in set) block()
}
override fun getNamedSubphases(startDepth: Int): List<Pair<Int, NamedCompilerPhase<*, *, *>>> =
override fun getNamedSubphases(startDepth: Int): List<Pair<Int, NamedCompilerPhase<*, *>>> =
listOf(startDepth to this) + lower.getNamedSubphases(startDepth + nlevels)
override fun toString() = "Compiler Phase @$name"
}
class SameTypeNamedPhaseWrapper<in Context : CommonBackendContext, Data>(
name: String,
description: String,
prerequisite: Set<AnyNamedPhase>,
lower: CompilerPhase<Context, Data, Data>,
preconditions: Set<Checker<Data>> = emptySet(),
postconditions: Set<Checker<Data>> = emptySet(),
stickyPostconditions: Set<Checker<Data>> = lower.stickyPostconditions,
actions: Set<Action<Data, Context>> = emptySet(),
nlevels: Int = 0
) : AbstractNamedPhaseWrapper<Context, Data, Data>(
name, description, prerequisite, lower, preconditions, postconditions, stickyPostconditions, actions, actions, nlevels
), SameTypeCompilerPhase<Context, Data>
@@ -23,7 +23,7 @@ private class CompositePhase<Context : CommonBackendContext, Input, Output>(
var result = phases.first().invoke(phaseConfig, currentState, context, input)
for ((previous, next) in phases.zip(phases.drop(1))) {
if (next !is SameTypeCompilerPhase<*, *>) {
// Discard `stickyPostcoditions`, they are useless since data type is changing.
// Discard `stickyPostconditions`, they are useless since data type is changing.
currentState = currentState.changeType()
}
currentState.stickyPostconditions.addAll(previous.stickyPostconditions)
@@ -58,7 +58,7 @@ fun <Context : CommonBackendContext> namedIrModulePhase(
stickyPostconditions: Set<Checker<IrModuleFragment>> = lower.stickyPostconditions,
actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper, validationAction),
nlevels: Int = 1
) = SameTypeNamedPhaseWrapper(
) = NamedCompilerPhase(
name,
description,
prerequisite,
@@ -80,7 +80,7 @@ fun <Context : CommonBackendContext> namedIrFilePhase(
stickyPostconditions: Set<Checker<IrFile>> = lower.stickyPostconditions,
actions: Set<Action<IrFile, Context>> = setOf(defaultDumper, validationAction),
nlevels: Int = 1
) = SameTypeNamedPhaseWrapper(
) = NamedCompilerPhase(
name,
description,
prerequisite,
@@ -102,7 +102,7 @@ fun <Context : CommonBackendContext, Element : IrElement> makeCustomPhase(
stickyPostconditions: Set<Checker<Element>> = emptySet(),
actions: Set<Action<Element, Context>> = setOf(defaultDumper, validationAction),
nlevels: Int = 1
) = SameTypeNamedPhaseWrapper(
) = NamedCompilerPhase(
name,
description,
prerequisite,
@@ -130,12 +130,13 @@ fun <Context : CommonBackendContext> namedUnitPhase(
prerequisite: Set<AnyNamedPhase> = emptySet(),
nlevels: Int = 1,
lower: CompilerPhase<Context, Unit, Unit>
) = SameTypeNamedPhaseWrapper(
) = NamedCompilerPhase(
name, description, prerequisite,
lower = lower,
nlevels = nlevels
)
@Suppress("unused") // Used in kotlin-native
fun <Context : CommonBackendContext> namedOpUnitPhase(
name: String,
description: String,
@@ -225,7 +226,7 @@ fun <Context : CommonBackendContext> makeIrModulePhase(
actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper, validationAction)
) = namedIrModulePhase(
name, description, prerequisite,
preconditions=preconditions,
preconditions = preconditions,
postconditions = postconditions,
stickyPostconditions = stickyPostconditions,
actions = actions,
@@ -243,29 +244,13 @@ fun <Context : CommonBackendContext> makeIrModulePhase(
}
)
fun <Context : CommonBackendContext, Input> unitPhase(
name: String,
description: String,
prerequisite: Set<AnyNamedPhase>,
preconditions: Set<Checker<Input>>,
op: Context.() -> Unit
) =
object : AbstractNamedPhaseWrapper<Context, Input, Unit>(
name, description, prerequisite,
preconditions = preconditions,
nlevels = 0,
lower = object : CompilerPhase<Context, Input, Unit> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {
context.op()
}
}
) {}
@Suppress("unused") // Used in kotlin-native
fun <Context : CommonBackendContext, Input> unitSink() = object : CompilerPhase<Context, Input, Unit> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {}
}
// Intermediate phases to change the object of transformations
@Suppress("unused") // Used in kotlin-native
fun <Context : CommonBackendContext, OldData, NewData> takeFromContext(op: (Context) -> NewData) =
object : CompilerPhase<Context, OldData, NewData> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<OldData>, context: Context, input: OldData) = op(context)
@@ -46,7 +46,7 @@ private fun makeCustomJsModulePhase(
description: String,
name: String,
prerequisite: Set<AnyNamedPhase> = emptySet()
) = SameTypeNamedPhaseWrapper(
) = NamedCompilerPhase(
name = name,
description = description,
prerequisite = prerequisite,
@@ -79,7 +79,7 @@ private fun <C> Action<IrElement, C>.toMultiModuleAction(): Action<Iterable<IrMo
}
sealed class Lowering(val name: String) {
abstract val modulePhase: SameTypeNamedPhaseWrapper<JsIrBackendContext, Iterable<IrModuleFragment>>
abstract val modulePhase: NamedCompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>>
}
class DeclarationLowering(
@@ -110,7 +110,7 @@ class BodyLowering(
class ModuleLowering(
name: String,
override val modulePhase: SameTypeNamedPhaseWrapper<JsIrBackendContext, Iterable<IrModuleFragment>>
override val modulePhase: NamedCompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>>
) : Lowering(name)
private fun makeDeclarationTransformerPhase(
@@ -127,7 +127,7 @@ private fun makeBodyLoweringPhase(
prerequisite: Set<Lowering> = emptySet()
) = BodyLowering(name, description, prerequisite.map { it.modulePhase }.toSet(), lowering)
fun SameTypeNamedPhaseWrapper<JsIrBackendContext, Iterable<IrModuleFragment>>.toModuleLowering() = ModuleLowering(this.name, this)
fun NamedCompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>>.toModuleLowering() = ModuleLowering(this.name, this)
private val validateIrBeforeLowering = makeCustomJsModulePhase(
{ context, module -> validationCallback(context, module) },
@@ -732,7 +732,7 @@ val loweringList = listOf<Lowering>(
// TODO comment? Eliminate ModuleLowering's? Don't filter them here?
val pirLowerings = loweringList.filter { it is DeclarationLowering || it is BodyLowering } + staticMembersLoweringPhase
val jsPhases = SameTypeNamedPhaseWrapper(
val jsPhases = NamedCompilerPhase(
name = "IrModuleLowering",
description = "IR module lowering",
prerequisite = emptySet(),
@@ -20,12 +20,15 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.ir.createStaticFunctionWithReceivers
import org.jetbrains.kotlin.backend.common.ir.moveBodyTo
import org.jetbrains.kotlin.backend.common.phaser.SameTypeNamedPhaseWrapper
import org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.common.phaser.then
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrReturn
@@ -45,7 +48,7 @@ private val callLoweringPhase = makeIrFilePhase(
description = "Generate calls of static functions for default parameters"
)
internal val staticDefaultFunctionPhase = SameTypeNamedPhaseWrapper(
internal val staticDefaultFunctionPhase = NamedCompilerPhase(
name = "StaticDefaultFunction",
description = "Make function adapters for default arguments static",
lower = functionDefinitionLoweringPhase then callLoweringPhase,