All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.backend.common.phaser.CompilerPhase.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * 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.phaser

import org.jetbrains.kotlin.backend.common.CommonBackendContext
import kotlin.system.measureTimeMillis

class PhaserState(
    val alreadyDone: MutableSet = mutableSetOf(),
    var depth: Int = 0,
    var phaseCount: Int = 0,
    val stickyPostconditions: MutableSet> = mutableSetOf()
)

// Copy state, forgetting the sticky postconditions (which will not be applicable to the new type)
fun  PhaserState.changeType() = PhaserState(alreadyDone, depth, phaseCount, mutableSetOf())

inline fun  PhaserState.downlevel(nlevels: Int, block: () -> R): R {
    depth += nlevels
    val result = block()
    depth -= nlevels
    return result
}

interface CompilerPhase {
    fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: Input): Output

    fun getNamedSubphases(startDepth: Int = 0): List>> = emptyList()

    // In phase trees, `stickyPostconditions` is inherited along the right edge to be used in `then`.
    val stickyPostconditions: Set> get() = emptySet()
}

fun  CompilerPhase.invokeToplevel(
    phaseConfig: PhaseConfig,
    context: Context,
    input: Input
): Output = invoke(phaseConfig, PhaserState(), context, input)

interface SameTypeCompilerPhase : CompilerPhase

// A failing checker should just throw an exception.
typealias Checker = (Data) -> Unit

typealias AnyNamedPhase = NamedCompilerPhase<*, *>

enum class BeforeOrAfter { BEFORE, AFTER }

data class ActionState(
    val config: PhaseConfig,
    val phase: AnyNamedPhase,
    val phaseCount: Int,
    val beforeOrAfter: BeforeOrAfter
)

typealias Action = (ActionState, Data, Context) -> Unit

infix operator fun  Action.plus(other: Action): Action =
    { phaseState, data, context ->
        this(phaseState, data, context)
        other(phaseState, data, context)
    }

class NamedCompilerPhase(
    val name: String,
    val description: String,
    val prerequisite: Set> = emptySet(),
    private val lower: CompilerPhase,
    val preconditions: Set> = emptySet(),
    val postconditions: Set> = emptySet(),
    override val stickyPostconditions: Set> = emptySet(),
    private val actions: Set> = emptySet(),
    private val nlevels: Int = 0
) : SameTypeCompilerPhase {
    override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: Data): Data {
        if (this !in phaseConfig.enabled) {
            return input
        }

        assert(phaserState.alreadyDone.containsAll(prerequisite)) {
            "Lowering $name: phases ${(prerequisite - phaserState.alreadyDone).map { it.name }} are required, but not satisfied"
        }

        context.inVerbosePhase = this in phaseConfig.verbose

        runBefore(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)
        phaserState.phaseCount++

        return output
    }

    private fun runBefore(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: Data) {
        val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.BEFORE)
        for (action in actions) action(state, input, context)

        if (phaseConfig.checkConditions) {
            for (pre in preconditions) pre(input)
        }
    }

    private fun runAfter(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, output: Data) {
        val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.AFTER)
        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) {
                for (post in phaserState.stickyPostconditions) post(output)
            }
        }
    }

    private fun runAndProfile(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, source: Data): Data {
        var result: Data? = null
        val msec = measureTimeMillis {
            result = phaserState.downlevel(nlevels) {
                lower.invoke(phaseConfig, phaserState, context, source)
            }
        }
        // TODO: use a proper logger
        println("${"\t".repeat(phaserState.depth)}$description: $msec msec")
        return result!!
    }

    override fun getNamedSubphases(startDepth: Int): List>> =
        listOf(startDepth to this) + lower.getNamedSubphases(startDepth + nlevels)

    override fun toString() = "Compiler Phase @$name"
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy