Phaser: Implement dumper and verifier as general actions

This commit is contained in:
Svyatoslav Kuzmich
2019-05-13 15:19:23 +03:00
parent 0702b88bf3
commit b07690fccf
12 changed files with 208 additions and 78 deletions
@@ -238,6 +238,18 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
) )
var namesExcludedFromDumping: Array<String>? by FreezableVar(null) var namesExcludedFromDumping: Array<String>? by FreezableVar(null)
@Argument(
value = "-Xdump-directory",
description = "Dump backend state into directory"
)
var dumpDirectory: String? by FreezableVar(null)
@Argument(
value = "-Xdump-fqname",
description = "FqName of declaration that should be dumped"
)
var dumpOnlyFqName: String? by FreezableVar(null)
@Argument( @Argument(
value = "-Xphases-to-validate-before", value = "-Xphases-to-validate-before",
description = "Validate backend state before these phases" description = "Validate backend state before these phases"
@@ -29,8 +29,9 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
import org.jetbrains.kotlin.ir.backend.js.KlibModuleRef import org.jetbrains.kotlin.ir.backend.js.KlibModuleRef
import org.jetbrains.kotlin.ir.backend.js.generateKLib
import org.jetbrains.kotlin.ir.backend.js.compile import org.jetbrains.kotlin.ir.backend.js.compile
import org.jetbrains.kotlin.ir.backend.js.generateKLib
import org.jetbrains.kotlin.ir.backend.js.jsPhases
import org.jetbrains.kotlin.js.config.EcmaVersion import org.jetbrains.kotlin.js.config.EcmaVersion
import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.JsConfig import org.jetbrains.kotlin.js.config.JsConfig
@@ -223,10 +224,13 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
} }
if (produceKind == ProduceKind.JS || produceKind == ProduceKind.DEFAULT) { if (produceKind == ProduceKind.JS || produceKind == ProduceKind.DEFAULT) {
val phaseConfig = createPhaseConfig(jsPhases, arguments, messageCollector)
val compiledModule = compile( val compiledModule = compile(
project, project,
sourcesFiles, sourcesFiles,
configuration, configuration,
phaseConfig,
immediateDependencies = dependencies, immediateDependencies = dependencies,
allDependencies = dependencies, allDependencies = dependencies,
friendDependencies = friendDependencies, friendDependencies = friendDependencies,
@@ -29,6 +29,8 @@ fun createPhaseConfig(
val bothDumpSet = phaseSetFromArguments(phases, arguments.phasesToDump, ::report) val bothDumpSet = phaseSetFromArguments(phases, arguments.phasesToDump, ::report)
val toDumpStateBefore = beforeDumpSet + bothDumpSet val toDumpStateBefore = beforeDumpSet + bothDumpSet
val toDumpStateAfter = afterDumpSet + bothDumpSet val toDumpStateAfter = afterDumpSet + bothDumpSet
val dumpDirectory = arguments.dumpDirectory
val dumpOnlyFqName = arguments.dumpOnlyFqName
val beforeValidateSet = phaseSetFromArguments(phases, arguments.phasesToValidateBefore, ::report) val beforeValidateSet = phaseSetFromArguments(phases, arguments.phasesToValidateBefore, ::report)
val afterValidateSet = phaseSetFromArguments(phases, arguments.phasesToValidateAfter, ::report) val afterValidateSet = phaseSetFromArguments(phases, arguments.phasesToValidateAfter, ::report)
val bothValidateSet = phaseSetFromArguments(phases, arguments.phasesToValidate, ::report) val bothValidateSet = phaseSetFromArguments(phases, arguments.phasesToValidate, ::report)
@@ -42,9 +44,20 @@ fun createPhaseConfig(
val checkStickyConditions = arguments.checkStickyPhaseConditions val checkStickyConditions = arguments.checkStickyPhaseConditions
return PhaseConfig( return PhaseConfig(
compoundPhase, phases, enabled, verbose, toDumpStateBefore, toDumpStateAfter, toValidateStateBefore, toValidateStateAfter, compoundPhase,
phases,
enabled,
verbose,
toDumpStateBefore,
toDumpStateAfter,
dumpDirectory,
dumpOnlyFqName,
toValidateStateBefore,
toValidateStateAfter,
namesOfElementsExcludedFromDumping, namesOfElementsExcludedFromDumping,
needProfiling, checkConditions, checkStickyConditions needProfiling,
checkConditions,
checkStickyConditions
).also { ).also {
if (arguments.listPhases) { if (arguments.listPhases) {
it.list() it.list()
@@ -11,11 +11,12 @@ import kotlin.system.measureTimeMillis
class PhaserState<Data>( class PhaserState<Data>(
val alreadyDone: MutableSet<AnyNamedPhase> = mutableSetOf(), val alreadyDone: MutableSet<AnyNamedPhase> = mutableSetOf(),
var depth: Int = 0, var depth: Int = 0,
var phaseCount: Int = 0,
val stickyPostconditions: MutableSet<Checker<Data>> = mutableSetOf() val stickyPostconditions: MutableSet<Checker<Data>> = mutableSetOf()
) )
// Copy state, forgetting the sticky postconditions (which will not be applicable to the new type) // 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, mutableSetOf()) fun <Input, Output> PhaserState<Input>.changeType() = PhaserState<Output>(alreadyDone, depth, phaseCount, mutableSetOf())
fun <R, D> PhaserState<D>.downlevel(nlevels: Int = 1, block: () -> R): R { fun <R, D> PhaserState<D>.downlevel(nlevels: Int = 1, block: () -> R): R {
@@ -51,15 +52,27 @@ interface NamedCompilerPhase<in Context : CommonBackendContext, Input, Output> :
val prerequisite: Set<AnyNamedPhase> get() = emptySet() val prerequisite: Set<AnyNamedPhase> get() = emptySet()
val preconditions: Set<Checker<Input>> val preconditions: Set<Checker<Input>>
val postconditions: Set<Checker<Output>> 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 } enum class BeforeOrAfter { BEFORE, AFTER }
interface PhaseDumperVerifier<in Context : CommonBackendContext, Data> { data class ActionState(
fun dump(phase: AnyNamedPhase, phaseConfig: PhaseConfig, data: Data, beforeOrAfter: BeforeOrAfter) val config: PhaseConfig,
fun verify(context: Context, data: Data) val phase: AnyNamedPhase,
} val phaseCount: Int,
val beforeOrAfter: BeforeOrAfter
)
typealias Action<Data, Context> = (ActionState, Data, Context) -> Unit
infix operator fun <Data, Context> Action<Data, Context>.plus(other: Action<Data, Context>): Action<Data, Context> =
{ phaseState, data, context ->
this(phaseState, data, context)
other(phaseState, data, context)
}
abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Input, Output>( abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Input, Output>(
override val name: String, override val name: String,
@@ -69,10 +82,10 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
override val preconditions: Set<Checker<Input>> = emptySet(), override val preconditions: Set<Checker<Input>> = emptySet(),
override val postconditions: Set<Checker<Output>> = emptySet(), override val postconditions: Set<Checker<Output>> = emptySet(),
override val stickyPostconditions: 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(),
private val nlevels: Int = 0 private val nlevels: Int = 0
) : NamedCompilerPhase<Context, Input, Output> { ) : NamedCompilerPhase<Context, Input, Output> {
abstract val inputDumperVerifier: PhaseDumperVerifier<Context, Input>
abstract val outputDumperVerifier: PhaseDumperVerifier<Context, Output>
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input): Output { override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input): Output {
if (this is SameTypeCompilerPhase<*, *> && if (this is SameTypeCompilerPhase<*, *> &&
@@ -88,18 +101,20 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
context.inVerbosePhase = this in phaseConfig.verbose context.inVerbosePhase = this in phaseConfig.verbose
runBefore(phaseConfig, context, input) runBefore(phaseConfig, phaserState, context, input)
val output = runBody(phaseConfig, phaserState, context, input) val output = runBody(phaseConfig, phaserState, context, input)
runAfter(phaseConfig, phaserState, context, output) runAfter(phaseConfig, phaserState, context, output)
phaserState.alreadyDone.add(this) phaserState.alreadyDone.add(this)
phaserState.phaseCount++
return output return output
} }
private fun runBefore(phaseConfig: PhaseConfig, context: Context, input: Input) { private fun runBefore(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {
checkAndRun(phaseConfig.toDumpStateBefore) { inputDumperVerifier.dump(this, phaseConfig, input, BeforeOrAfter.BEFORE) } val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.BEFORE)
checkAndRun(phaseConfig.toValidateStateBefore) { inputDumperVerifier.verify(context, input) } for (action in actionsBefore) action(state, input, context)
if (phaseConfig.checkConditions) { if (phaseConfig.checkConditions) {
for (pre in preconditions) pre(input) for (pre in preconditions) pre(input)
} }
@@ -116,8 +131,9 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
} }
private fun runAfter(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, output: Output) { private fun runAfter(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, output: Output) {
checkAndRun(phaseConfig.toDumpStateAfter) { outputDumperVerifier.dump(this, phaseConfig, output, BeforeOrAfter.AFTER) } val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.AFTER)
checkAndRun(phaseConfig.toValidateStateAfter) { outputDumperVerifier.verify(context, output) } for (action in actionsAfter) action(state, output, context)
if (phaseConfig.checkConditions) { if (phaseConfig.checkConditions) {
for (post in postconditions) post(output) for (post in postconditions) post(output)
for (post in stickyPostconditions) post(output) for (post in stickyPostconditions) post(output)
@@ -158,11 +174,8 @@ class SameTypeNamedPhaseWrapper<in Context : CommonBackendContext, Data>(
preconditions: Set<Checker<Data>> = emptySet(), preconditions: Set<Checker<Data>> = emptySet(),
postconditions: Set<Checker<Data>> = emptySet(), postconditions: Set<Checker<Data>> = emptySet(),
stickyPostconditions: Set<Checker<Data>> = lower.stickyPostconditions, stickyPostconditions: Set<Checker<Data>> = lower.stickyPostconditions,
nlevels: Int = 0, actions: Set<Action<Data, Context>> = emptySet(),
val dumperVerifier: PhaseDumperVerifier<Context, Data> nlevels: Int = 0
) : AbstractNamedPhaseWrapper<Context, Data, Data>( ) : AbstractNamedPhaseWrapper<Context, Data, Data>(
name, description, prerequisite, lower, preconditions, postconditions, stickyPostconditions, nlevels name, description, prerequisite, lower, preconditions, postconditions, stickyPostconditions, actions, actions, nlevels
), SameTypeCompilerPhase<Context, Data> { ), SameTypeCompilerPhase<Context, Data>
override val inputDumperVerifier get() = dumperVerifier
override val outputDumperVerifier get() = dumperVerifier
}
@@ -5,48 +5,115 @@
package org.jetbrains.kotlin.backend.common.phaser package org.jetbrains.kotlin.backend.common.phaser
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.name
import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.FqName
import java.io.File
abstract class IrPhaseDumperVerifier<in Context : CommonBackendContext, Data : IrElement>( private val IrElement.elementName: String
val verifier: (Context, Data) -> Unit get() = when (this) {
) : PhaseDumperVerifier<Context, Data> { is IrModuleFragment ->
abstract fun Data.getElementName(): String this.name.asString()
// TODO: use a proper logger. is IrFile ->
override fun dump(phase: AnyNamedPhase, phaseConfig: PhaseConfig, data: Data, beforeOrAfter: BeforeOrAfter) { this.name
fun separator(title: String) = println("\n\n--- $title ----------------------\n")
if (!shouldBeDumped(phaseConfig, data)) return else ->
this.toString()
val beforeOrAfterStr = beforeOrAfter.name.toLowerCase()
val title = "IR for ${data.getElementName()} $beforeOrAfterStr ${phase.description}"
separator(title)
println(data.dump())
} }
override fun verify(context: Context, data: Data) = verifier(context, data) private fun ActionState.isDumpNeeded() =
phase in when (beforeOrAfter) {
BeforeOrAfter.BEFORE -> config.toDumpStateBefore
BeforeOrAfter.AFTER -> config.toDumpStateAfter
}
private fun shouldBeDumped(phaseConfig: PhaseConfig, input: Data) = private fun ActionState.isValidationNeeded() =
input.getElementName() !in phaseConfig.namesOfElementsExcludedFromDumping phase in when (beforeOrAfter) {
BeforeOrAfter.BEFORE -> config.toValidateStateBefore
BeforeOrAfter.AFTER -> config.toValidateStateAfter
}
fun <Data, Context> makeDumpAction(dumper: Action<Data, Context>): Action<Data, Context> =
{ phaseState, data, context ->
if (phaseState.isDumpNeeded())
dumper(phaseState, data, context)
}
fun <Data, Context> makeVerifyAction(verifier: (Context, Data) -> Unit): Action<Data, Context> =
{ phaseState, data, context ->
if (phaseState.isValidationNeeded())
verifier(context, data)
}
fun dumpIrElement(actionState: ActionState, data: IrElement, context: Any?): String {
val beforeOrAfterStr = actionState.beforeOrAfter.name.toLowerCase()
var dumpText: String = ""
val elementName: String
val dumpOnlyFqName = actionState.config.dumpOnlyFqName
if (dumpOnlyFqName != null) {
elementName = dumpOnlyFqName
data.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitDeclaration(declaration: IrDeclaration) {
if (declaration is IrDeclarationWithName && FqName(dumpOnlyFqName) == declaration.fqNameWhenAvailable) {
dumpText += declaration.dump()
} else {
super.visitDeclaration(declaration)
}
}
})
} else {
elementName = data.elementName
dumpText = data.dump()
}
val title = "-- IR for $elementName $beforeOrAfterStr ${actionState.phase.description}\n"
return title + dumpText
} }
class IrFileDumperVerifier<in Context : CommonBackendContext>(verifier: (Context, IrFile) -> Unit) : typealias Dumper<Data, Context> = (ActionState, Data, Context) -> String?
IrPhaseDumperVerifier<Context, IrFile>(verifier) {
override fun IrFile.getElementName() = name
}
class IrModuleDumperVerifier<in Context : CommonBackendContext>(verifier: (Context, IrModuleFragment) -> Unit) : fun <Data, Context> dumpToFile(
IrPhaseDumperVerifier<Context, IrModuleFragment>(verifier) { fileExtension: String,
override fun IrModuleFragment.getElementName() = name.asString() dumper: Dumper<Data, Context>
} ): Action<Data, Context> =
fun(actionState: ActionState, data: Data, context: Context) {
val directoryPath = actionState.config.dumpToDirectory ?: return
val dumpContent = dumper(actionState, data, context) ?: return
class EmptyDumperVerifier<in Context : CommonBackendContext, Data> : PhaseDumperVerifier<Context, Data> { val directoryFile = File(directoryPath)
override fun dump(phase: AnyNamedPhase, phaseConfig: PhaseConfig, data: Data, beforeOrAfter: BeforeOrAfter) {} if (!directoryFile.isDirectory)
override fun verify(context: Context, data: Data) {} if (!directoryFile.mkdirs())
} error("Can't create directory for IR dumps at $directoryPath")
// Make dump files in a directory sorted by ID
val phaseIdFormatted = "%02d".format(actionState.phaseCount)
val fileName = "${phaseIdFormatted}_${actionState.phase.name}.$fileExtension"
File(directoryFile, fileName).writeText(dumpContent)
}
fun <Data, Context> dumpToStdout(
dumper: Dumper<Data, Context>
): Action<Data, Context> =
fun(actionState: ActionState, data: Data, context: Context) {
if (actionState.config.dumpToDirectory != null) return
val dumpContent = dumper(actionState, data, context) ?: return
println("\n\n----------------------------------------------")
println(dumpContent)
println()
}
val defaultDumper = makeDumpAction(dumpToStdout(::dumpIrElement) + dumpToFile("ir", ::dumpIrElement))
@@ -54,7 +54,7 @@ fun <Context : CommonBackendContext> namedIrModulePhase(
preconditions: Set<Checker<IrModuleFragment>> = emptySet(), preconditions: Set<Checker<IrModuleFragment>> = emptySet(),
postconditions: Set<Checker<IrModuleFragment>> = emptySet(), postconditions: Set<Checker<IrModuleFragment>> = emptySet(),
stickyPostconditions: Set<Checker<IrModuleFragment>> = lower.stickyPostconditions, stickyPostconditions: Set<Checker<IrModuleFragment>> = lower.stickyPostconditions,
verify: (Context, IrModuleFragment) -> Unit = { _, _ -> }, actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper),
nlevels: Int = 1 nlevels: Int = 1
) = SameTypeNamedPhaseWrapper( ) = SameTypeNamedPhaseWrapper(
name, name,
@@ -64,8 +64,8 @@ fun <Context : CommonBackendContext> namedIrModulePhase(
preconditions, preconditions,
postconditions, postconditions,
stickyPostconditions, stickyPostconditions,
nlevels, actions,
IrModuleDumperVerifier(verify) nlevels
) )
fun <Context : CommonBackendContext> namedIrFilePhase( fun <Context : CommonBackendContext> namedIrFilePhase(
@@ -76,7 +76,7 @@ fun <Context : CommonBackendContext> namedIrFilePhase(
preconditions: Set<Checker<IrFile>> = emptySet(), preconditions: Set<Checker<IrFile>> = emptySet(),
postconditions: Set<Checker<IrFile>> = emptySet(), postconditions: Set<Checker<IrFile>> = emptySet(),
stickyPostconditions: Set<Checker<IrFile>> = lower.stickyPostconditions, stickyPostconditions: Set<Checker<IrFile>> = lower.stickyPostconditions,
verify: (Context, IrFile) -> Unit = { _, _ -> }, actions: Set<Action<IrFile, Context>> = setOf(defaultDumper),
nlevels: Int = 1 nlevels: Int = 1
) = SameTypeNamedPhaseWrapper( ) = SameTypeNamedPhaseWrapper(
name, name,
@@ -86,8 +86,8 @@ fun <Context : CommonBackendContext> namedIrFilePhase(
preconditions, preconditions,
postconditions, postconditions,
stickyPostconditions, stickyPostconditions,
nlevels, actions,
IrFileDumperVerifier(verify) nlevels
) )
fun <Context : CommonBackendContext> namedUnitPhase( fun <Context : CommonBackendContext> namedUnitPhase(
@@ -99,8 +99,7 @@ fun <Context : CommonBackendContext> namedUnitPhase(
) = SameTypeNamedPhaseWrapper( ) = SameTypeNamedPhaseWrapper(
name, description, prerequisite, name, description, prerequisite,
lower = lower, lower = lower,
nlevels = nlevels, nlevels = nlevels
dumperVerifier = EmptyDumperVerifier()
) )
fun <Context : CommonBackendContext> namedOpUnitPhase( fun <Context : CommonBackendContext> namedOpUnitPhase(
@@ -125,14 +124,14 @@ fun <Context : CommonBackendContext> performByIrFile(
preconditions: Set<Checker<IrModuleFragment>> = emptySet(), preconditions: Set<Checker<IrModuleFragment>> = emptySet(),
postconditions: Set<Checker<IrModuleFragment>> = emptySet(), postconditions: Set<Checker<IrModuleFragment>> = emptySet(),
stickyPostconditions: Set<Checker<IrModuleFragment>> = emptySet(), stickyPostconditions: Set<Checker<IrModuleFragment>> = emptySet(),
verify: (Context, IrModuleFragment) -> Unit = { _, _ -> }, actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper),
lower: CompilerPhase<Context, IrFile, IrFile> lower: CompilerPhase<Context, IrFile, IrFile>
) = namedIrModulePhase( ) = namedIrModulePhase(
name, description, prerequisite, name, description, prerequisite,
preconditions = preconditions, preconditions = preconditions,
postconditions = postconditions, postconditions = postconditions,
stickyPostconditions = stickyPostconditions, stickyPostconditions = stickyPostconditions,
verify = verify, actions = actions,
nlevels = 1, nlevels = 1,
lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> { lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> {
override fun invoke( override fun invoke(
@@ -161,13 +160,13 @@ fun <Context : CommonBackendContext> makeIrFilePhase(
preconditions: Set<Checker<IrFile>> = emptySet(), preconditions: Set<Checker<IrFile>> = emptySet(),
postconditions: Set<Checker<IrFile>> = emptySet(), postconditions: Set<Checker<IrFile>> = emptySet(),
stickyPostconditions: Set<Checker<IrFile>> = emptySet(), stickyPostconditions: Set<Checker<IrFile>> = emptySet(),
verify: (Context, IrFile) -> Unit = { _, _ -> } actions: Set<Action<IrFile, Context>> = setOf(defaultDumper)
) = namedIrFilePhase( ) = namedIrFilePhase(
name, description, prerequisite, name, description, prerequisite,
preconditions = preconditions, preconditions = preconditions,
postconditions = postconditions, postconditions = postconditions,
stickyPostconditions = stickyPostconditions, stickyPostconditions = stickyPostconditions,
verify = verify, actions = actions,
nlevels = 0, nlevels = 0,
lower = object : SameTypeCompilerPhase<Context, IrFile> { lower = object : SameTypeCompilerPhase<Context, IrFile> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<IrFile>, context: Context, input: IrFile): IrFile { override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<IrFile>, context: Context, input: IrFile): IrFile {
@@ -185,13 +184,13 @@ fun <Context : CommonBackendContext> makeIrModulePhase(
preconditions: Set<Checker<IrModuleFragment>> = emptySet(), preconditions: Set<Checker<IrModuleFragment>> = emptySet(),
postconditions: Set<Checker<IrModuleFragment>> = emptySet(), postconditions: Set<Checker<IrModuleFragment>> = emptySet(),
stickyPostconditions: Set<Checker<IrModuleFragment>> = emptySet(), stickyPostconditions: Set<Checker<IrModuleFragment>> = emptySet(),
verify: (Context, IrModuleFragment) -> Unit = { _, _ -> } actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper)
) = namedIrModulePhase( ) = namedIrModulePhase(
name, description, prerequisite, name, description, prerequisite,
preconditions=preconditions, preconditions=preconditions,
postconditions = postconditions, postconditions = postconditions,
stickyPostconditions = stickyPostconditions, stickyPostconditions = stickyPostconditions,
verify = verify, actions = actions,
nlevels = 0, nlevels = 0,
lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> { lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> {
override fun invoke( override fun invoke(
@@ -222,10 +221,7 @@ fun <Context : CommonBackendContext, Input> unitPhase(
context.op() context.op()
} }
} }
) { ) {}
override val inputDumperVerifier = EmptyDumperVerifier<Context, Input>()
override val outputDumperVerifier = EmptyDumperVerifier<Context, Unit>()
}
fun <Context : CommonBackendContext, Input> unitSink() = object : CompilerPhase<Context, Input, Unit> { fun <Context : CommonBackendContext, Input> unitSink() = object : CompilerPhase<Context, Input, Unit> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {} override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {}
@@ -19,6 +19,8 @@ class PhaseConfig(
val verbose: Set<AnyNamedPhase> = emptySet(), val verbose: Set<AnyNamedPhase> = emptySet(),
val toDumpStateBefore: Set<AnyNamedPhase> = emptySet(), val toDumpStateBefore: Set<AnyNamedPhase> = emptySet(),
val toDumpStateAfter: Set<AnyNamedPhase> = emptySet(), val toDumpStateAfter: Set<AnyNamedPhase> = emptySet(),
val dumpToDirectory: String? = null,
val dumpOnlyFqName: String? = null,
val toValidateStateBefore: Set<AnyNamedPhase> = emptySet(), val toValidateStateBefore: Set<AnyNamedPhase> = emptySet(),
val toValidateStateAfter: Set<AnyNamedPhase> = emptySet(), val toValidateStateAfter: Set<AnyNamedPhase> = emptySet(),
val namesOfElementsExcludedFromDumping: Set<String> = emptySet(), val namesOfElementsExcludedFromDumping: Set<String> = emptySet(),
@@ -33,12 +33,14 @@ private fun validationCallback(context: JsIrBackendContext, module: IrModuleFrag
module.accept(CheckDeclarationParentsVisitor, null) module.accept(CheckDeclarationParentsVisitor, null)
} }
val validationAction = makeVerifyAction(::validationCallback)
private fun makeJsModulePhase( private fun makeJsModulePhase(
lowering: (JsIrBackendContext) -> FileLoweringPass, lowering: (JsIrBackendContext) -> FileLoweringPass,
name: String, name: String,
description: String, description: String,
prerequisite: Set<AnyNamedPhase> = emptySet() prerequisite: Set<AnyNamedPhase> = emptySet()
) = makeIrModulePhase<JsIrBackendContext>(lowering, name, description, prerequisite, verify = ::validationCallback) ) = makeIrModulePhase<JsIrBackendContext>(lowering, name, description, prerequisite, actions = setOf(validationAction, defaultDumper))
private fun makeCustomJsModulePhase( private fun makeCustomJsModulePhase(
op: (JsIrBackendContext, IrModuleFragment) -> Unit, op: (JsIrBackendContext, IrModuleFragment) -> Unit,
@@ -49,7 +51,7 @@ private fun makeCustomJsModulePhase(
name, name,
description, description,
prerequisite, prerequisite,
verify = ::validationCallback, actions = setOf(defaultDumper, validationAction),
nlevels = 0, nlevels = 0,
lower = object : SameTypeCompilerPhase<JsIrBackendContext, IrModuleFragment> { lower = object : SameTypeCompilerPhase<JsIrBackendContext, IrModuleFragment> {
override fun invoke( override fun invoke(
@@ -19,7 +19,7 @@ fun compile(
project: Project, project: Project,
files: List<KtFile>, files: List<KtFile>,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
phaseConfig: PhaseConfig = PhaseConfig(jsPhases), phaseConfig: PhaseConfig,
immediateDependencies: List<KlibModuleRef>, immediateDependencies: List<KlibModuleRef>,
allDependencies: List<KlibModuleRef>, allDependencies: List<KlibModuleRef>,
friendDependencies: List<KlibModuleRef>, friendDependencies: List<KlibModuleRef>,
+2
View File
@@ -15,6 +15,8 @@ where advanced options include:
-Xcoroutines={enable|warn|error} -Xcoroutines={enable|warn|error}
Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
-Xdisable-phases Disable backend phases -Xdisable-phases Disable backend phases
-Xdump-directory Dump backend state into directory
-Xdump-fqname FqName of declaration that should be dumped
-Xdump-perf=<path> Dump detailed performance statistics to the specified file -Xdump-perf=<path> Dump detailed performance statistics to the specified file
-Xeffect-system Enable experimental language feature: effect system -Xeffect-system Enable experimental language feature: effect system
-Xexperimental=<fq.name> Enable and propagate usages of experimental API for marker annotation with the given fully qualified name -Xexperimental=<fq.name> Enable and propagate usages of experimental API for marker annotation with the given fully qualified name
+2
View File
@@ -79,6 +79,8 @@ where advanced options include:
-Xcoroutines={enable|warn|error} -Xcoroutines={enable|warn|error}
Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
-Xdisable-phases Disable backend phases -Xdisable-phases Disable backend phases
-Xdump-directory Dump backend state into directory
-Xdump-fqname FqName of declaration that should be dumped
-Xdump-perf=<path> Dump detailed performance statistics to the specified file -Xdump-perf=<path> Dump detailed performance statistics to the specified file
-Xeffect-system Enable experimental language feature: effect system -Xeffect-system Enable experimental language feature: effect system
-Xexperimental=<fq.name> Enable and propagate usages of experimental API for marker annotation with the given fully qualified name -Xexperimental=<fq.name> Enable and propagate usages of experimental API for marker annotation with the given fully qualified name
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.js.test package org.jetbrains.kotlin.js.test
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.backend.common.phaser.toPhaseMap
import org.jetbrains.kotlin.ir.backend.js.KlibModuleRef import org.jetbrains.kotlin.ir.backend.js.KlibModuleRef
import org.jetbrains.kotlin.ir.backend.js.compile import org.jetbrains.kotlin.ir.backend.js.compile
import org.jetbrains.kotlin.ir.backend.js.generateKLib import org.jetbrains.kotlin.ir.backend.js.generateKLib
@@ -90,11 +90,28 @@ abstract class BasicIrBoxTest(
} }
if (isMainModule) { if (isMainModule) {
val debugMode = false
val phaseConfig = if (debugMode) {
val allPhasesSet = jsPhases.toPhaseMap().values.toSet()
val dumpOutputDir = File(outputFile.parent, outputFile.nameWithoutExtension + "-irdump")
println("\n ------ Dumping phases to file://$dumpOutputDir")
PhaseConfig(
jsPhases,
dumpToDirectory = dumpOutputDir.path,
toDumpStateAfter = allPhasesSet,
toValidateStateAfter = allPhasesSet,
dumpOnlyFqName = null
)
} else {
PhaseConfig(jsPhases)
}
val jsCode = compile( val jsCode = compile(
project = config.project, project = config.project,
files = filesToCompile, files = filesToCompile,
configuration = config.configuration, configuration = config.configuration,
phaseConfig = config.configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jsPhases), phaseConfig = phaseConfig,
immediateDependencies = dependencies, immediateDependencies = dependencies,
allDependencies = allDependencies, allDependencies = allDependencies,
friendDependencies = emptyList(), friendDependencies = emptyList(),