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:
+33
-71
@@ -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>
|
||||
|
||||
+9
-24
@@ -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(),
|
||||
|
||||
+6
-3
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user