Phaser: Implement dumper and verifier as general actions
This commit is contained in:
+12
@@ -238,6 +238,18 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
|
||||
)
|
||||
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(
|
||||
value = "-Xphases-to-validate-before",
|
||||
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.IncrementalResultsConsumer
|
||||
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.generateKLib
|
||||
import org.jetbrains.kotlin.ir.backend.js.jsPhases
|
||||
import org.jetbrains.kotlin.js.config.EcmaVersion
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
@@ -223,10 +224,13 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
}
|
||||
|
||||
if (produceKind == ProduceKind.JS || produceKind == ProduceKind.DEFAULT) {
|
||||
val phaseConfig = createPhaseConfig(jsPhases, arguments, messageCollector)
|
||||
|
||||
val compiledModule = compile(
|
||||
project,
|
||||
sourcesFiles,
|
||||
configuration,
|
||||
phaseConfig,
|
||||
immediateDependencies = dependencies,
|
||||
allDependencies = dependencies,
|
||||
friendDependencies = friendDependencies,
|
||||
|
||||
@@ -29,6 +29,8 @@ fun createPhaseConfig(
|
||||
val bothDumpSet = phaseSetFromArguments(phases, arguments.phasesToDump, ::report)
|
||||
val toDumpStateBefore = beforeDumpSet + bothDumpSet
|
||||
val toDumpStateAfter = afterDumpSet + bothDumpSet
|
||||
val dumpDirectory = arguments.dumpDirectory
|
||||
val dumpOnlyFqName = arguments.dumpOnlyFqName
|
||||
val beforeValidateSet = phaseSetFromArguments(phases, arguments.phasesToValidateBefore, ::report)
|
||||
val afterValidateSet = phaseSetFromArguments(phases, arguments.phasesToValidateAfter, ::report)
|
||||
val bothValidateSet = phaseSetFromArguments(phases, arguments.phasesToValidate, ::report)
|
||||
@@ -42,9 +44,20 @@ fun createPhaseConfig(
|
||||
val checkStickyConditions = arguments.checkStickyPhaseConditions
|
||||
|
||||
return PhaseConfig(
|
||||
compoundPhase, phases, enabled, verbose, toDumpStateBefore, toDumpStateAfter, toValidateStateBefore, toValidateStateAfter,
|
||||
compoundPhase,
|
||||
phases,
|
||||
enabled,
|
||||
verbose,
|
||||
toDumpStateBefore,
|
||||
toDumpStateAfter,
|
||||
dumpDirectory,
|
||||
dumpOnlyFqName,
|
||||
toValidateStateBefore,
|
||||
toValidateStateAfter,
|
||||
namesOfElementsExcludedFromDumping,
|
||||
needProfiling, checkConditions, checkStickyConditions
|
||||
needProfiling,
|
||||
checkConditions,
|
||||
checkStickyConditions
|
||||
).also {
|
||||
if (arguments.listPhases) {
|
||||
it.list()
|
||||
|
||||
+33
-20
@@ -11,11 +11,12 @@ import kotlin.system.measureTimeMillis
|
||||
class PhaserState<Data>(
|
||||
val alreadyDone: MutableSet<AnyNamedPhase> = mutableSetOf(),
|
||||
var depth: Int = 0,
|
||||
var phaseCount: Int = 0,
|
||||
val stickyPostconditions: MutableSet<Checker<Data>> = mutableSetOf()
|
||||
)
|
||||
|
||||
// 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 {
|
||||
@@ -51,15 +52,27 @@ interface NamedCompilerPhase<in Context : CommonBackendContext, Input, Output> :
|
||||
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<*, *, *>
|
||||
enum class BeforeOrAfter { BEFORE, AFTER }
|
||||
|
||||
interface PhaseDumperVerifier<in Context : CommonBackendContext, Data> {
|
||||
fun dump(phase: AnyNamedPhase, phaseConfig: PhaseConfig, data: Data, beforeOrAfter: BeforeOrAfter)
|
||||
fun verify(context: Context, data: Data)
|
||||
}
|
||||
data class ActionState(
|
||||
val config: PhaseConfig,
|
||||
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>(
|
||||
override val name: String,
|
||||
@@ -69,10 +82,10 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
|
||||
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(),
|
||||
private val nlevels: Int = 0
|
||||
) : 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 {
|
||||
if (this is SameTypeCompilerPhase<*, *> &&
|
||||
@@ -88,18 +101,20 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
|
||||
|
||||
context.inVerbosePhase = this in phaseConfig.verbose
|
||||
|
||||
runBefore(phaseConfig, context, input)
|
||||
runBefore(phaseConfig, phaserState, context, input)
|
||||
val output = runBody(phaseConfig, phaserState, context, input)
|
||||
runAfter(phaseConfig, phaserState, context, output)
|
||||
|
||||
phaserState.alreadyDone.add(this)
|
||||
phaserState.phaseCount++
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
private fun runBefore(phaseConfig: PhaseConfig, context: Context, input: Input) {
|
||||
checkAndRun(phaseConfig.toDumpStateBefore) { inputDumperVerifier.dump(this, phaseConfig, input, BeforeOrAfter.BEFORE) }
|
||||
checkAndRun(phaseConfig.toValidateStateBefore) { inputDumperVerifier.verify(context, input) }
|
||||
private fun runBefore(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {
|
||||
val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.BEFORE)
|
||||
for (action in actionsBefore) action(state, input, context)
|
||||
|
||||
if (phaseConfig.checkConditions) {
|
||||
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) {
|
||||
checkAndRun(phaseConfig.toDumpStateAfter) { outputDumperVerifier.dump(this, phaseConfig, output, BeforeOrAfter.AFTER) }
|
||||
checkAndRun(phaseConfig.toValidateStateAfter) { outputDumperVerifier.verify(context, output) }
|
||||
val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.AFTER)
|
||||
for (action in actionsAfter) action(state, output, context)
|
||||
|
||||
if (phaseConfig.checkConditions) {
|
||||
for (post in postconditions) post(output)
|
||||
for (post in stickyPostconditions) post(output)
|
||||
@@ -158,11 +174,8 @@ class SameTypeNamedPhaseWrapper<in Context : CommonBackendContext, Data>(
|
||||
preconditions: Set<Checker<Data>> = emptySet(),
|
||||
postconditions: Set<Checker<Data>> = emptySet(),
|
||||
stickyPostconditions: Set<Checker<Data>> = lower.stickyPostconditions,
|
||||
nlevels: Int = 0,
|
||||
val dumperVerifier: PhaseDumperVerifier<Context, Data>
|
||||
actions: Set<Action<Data, Context>> = emptySet(),
|
||||
nlevels: Int = 0
|
||||
) : AbstractNamedPhaseWrapper<Context, Data, Data>(
|
||||
name, description, prerequisite, lower, preconditions, postconditions, stickyPostconditions, nlevels
|
||||
), SameTypeCompilerPhase<Context, Data> {
|
||||
override val inputDumperVerifier get() = dumperVerifier
|
||||
override val outputDumperVerifier get() = dumperVerifier
|
||||
}
|
||||
name, description, prerequisite, lower, preconditions, postconditions, stickyPostconditions, actions, actions, nlevels
|
||||
), SameTypeCompilerPhase<Context, Data>
|
||||
|
||||
+99
-32
@@ -5,48 +5,115 @@
|
||||
|
||||
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.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.name
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
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>(
|
||||
val verifier: (Context, Data) -> Unit
|
||||
) : PhaseDumperVerifier<Context, Data> {
|
||||
abstract fun Data.getElementName(): String
|
||||
private val IrElement.elementName: String
|
||||
get() = when (this) {
|
||||
is IrModuleFragment ->
|
||||
this.name.asString()
|
||||
|
||||
// TODO: use a proper logger.
|
||||
override fun dump(phase: AnyNamedPhase, phaseConfig: PhaseConfig, data: Data, beforeOrAfter: BeforeOrAfter) {
|
||||
fun separator(title: String) = println("\n\n--- $title ----------------------\n")
|
||||
is IrFile ->
|
||||
this.name
|
||||
|
||||
if (!shouldBeDumped(phaseConfig, data)) return
|
||||
|
||||
val beforeOrAfterStr = beforeOrAfter.name.toLowerCase()
|
||||
val title = "IR for ${data.getElementName()} $beforeOrAfterStr ${phase.description}"
|
||||
separator(title)
|
||||
println(data.dump())
|
||||
else ->
|
||||
this.toString()
|
||||
}
|
||||
|
||||
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) =
|
||||
input.getElementName() !in phaseConfig.namesOfElementsExcludedFromDumping
|
||||
private fun ActionState.isValidationNeeded() =
|
||||
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) :
|
||||
IrPhaseDumperVerifier<Context, IrFile>(verifier) {
|
||||
override fun IrFile.getElementName() = name
|
||||
}
|
||||
typealias Dumper<Data, Context> = (ActionState, Data, Context) -> String?
|
||||
|
||||
class IrModuleDumperVerifier<in Context : CommonBackendContext>(verifier: (Context, IrModuleFragment) -> Unit) :
|
||||
IrPhaseDumperVerifier<Context, IrModuleFragment>(verifier) {
|
||||
override fun IrModuleFragment.getElementName() = name.asString()
|
||||
}
|
||||
fun <Data, Context> dumpToFile(
|
||||
fileExtension: String,
|
||||
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> {
|
||||
override fun dump(phase: AnyNamedPhase, phaseConfig: PhaseConfig, data: Data, beforeOrAfter: BeforeOrAfter) {}
|
||||
override fun verify(context: Context, data: Data) {}
|
||||
}
|
||||
val directoryFile = File(directoryPath)
|
||||
if (!directoryFile.isDirectory)
|
||||
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))
|
||||
+14
-18
@@ -54,7 +54,7 @@ fun <Context : CommonBackendContext> namedIrModulePhase(
|
||||
preconditions: Set<Checker<IrModuleFragment>> = emptySet(),
|
||||
postconditions: Set<Checker<IrModuleFragment>> = emptySet(),
|
||||
stickyPostconditions: Set<Checker<IrModuleFragment>> = lower.stickyPostconditions,
|
||||
verify: (Context, IrModuleFragment) -> Unit = { _, _ -> },
|
||||
actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper),
|
||||
nlevels: Int = 1
|
||||
) = SameTypeNamedPhaseWrapper(
|
||||
name,
|
||||
@@ -64,8 +64,8 @@ fun <Context : CommonBackendContext> namedIrModulePhase(
|
||||
preconditions,
|
||||
postconditions,
|
||||
stickyPostconditions,
|
||||
nlevels,
|
||||
IrModuleDumperVerifier(verify)
|
||||
actions,
|
||||
nlevels
|
||||
)
|
||||
|
||||
fun <Context : CommonBackendContext> namedIrFilePhase(
|
||||
@@ -76,7 +76,7 @@ fun <Context : CommonBackendContext> namedIrFilePhase(
|
||||
preconditions: Set<Checker<IrFile>> = emptySet(),
|
||||
postconditions: Set<Checker<IrFile>> = emptySet(),
|
||||
stickyPostconditions: Set<Checker<IrFile>> = lower.stickyPostconditions,
|
||||
verify: (Context, IrFile) -> Unit = { _, _ -> },
|
||||
actions: Set<Action<IrFile, Context>> = setOf(defaultDumper),
|
||||
nlevels: Int = 1
|
||||
) = SameTypeNamedPhaseWrapper(
|
||||
name,
|
||||
@@ -86,8 +86,8 @@ fun <Context : CommonBackendContext> namedIrFilePhase(
|
||||
preconditions,
|
||||
postconditions,
|
||||
stickyPostconditions,
|
||||
nlevels,
|
||||
IrFileDumperVerifier(verify)
|
||||
actions,
|
||||
nlevels
|
||||
)
|
||||
|
||||
fun <Context : CommonBackendContext> namedUnitPhase(
|
||||
@@ -99,8 +99,7 @@ fun <Context : CommonBackendContext> namedUnitPhase(
|
||||
) = SameTypeNamedPhaseWrapper(
|
||||
name, description, prerequisite,
|
||||
lower = lower,
|
||||
nlevels = nlevels,
|
||||
dumperVerifier = EmptyDumperVerifier()
|
||||
nlevels = nlevels
|
||||
)
|
||||
|
||||
fun <Context : CommonBackendContext> namedOpUnitPhase(
|
||||
@@ -125,14 +124,14 @@ fun <Context : CommonBackendContext> performByIrFile(
|
||||
preconditions: Set<Checker<IrModuleFragment>> = emptySet(),
|
||||
postconditions: 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>
|
||||
) = namedIrModulePhase(
|
||||
name, description, prerequisite,
|
||||
preconditions = preconditions,
|
||||
postconditions = postconditions,
|
||||
stickyPostconditions = stickyPostconditions,
|
||||
verify = verify,
|
||||
actions = actions,
|
||||
nlevels = 1,
|
||||
lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> {
|
||||
override fun invoke(
|
||||
@@ -161,13 +160,13 @@ fun <Context : CommonBackendContext> makeIrFilePhase(
|
||||
preconditions: Set<Checker<IrFile>> = emptySet(),
|
||||
postconditions: Set<Checker<IrFile>> = emptySet(),
|
||||
stickyPostconditions: Set<Checker<IrFile>> = emptySet(),
|
||||
verify: (Context, IrFile) -> Unit = { _, _ -> }
|
||||
actions: Set<Action<IrFile, Context>> = setOf(defaultDumper)
|
||||
) = namedIrFilePhase(
|
||||
name, description, prerequisite,
|
||||
preconditions = preconditions,
|
||||
postconditions = postconditions,
|
||||
stickyPostconditions = stickyPostconditions,
|
||||
verify = verify,
|
||||
actions = actions,
|
||||
nlevels = 0,
|
||||
lower = object : SameTypeCompilerPhase<Context, 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(),
|
||||
postconditions: Set<Checker<IrModuleFragment>> = emptySet(),
|
||||
stickyPostconditions: Set<Checker<IrModuleFragment>> = emptySet(),
|
||||
verify: (Context, IrModuleFragment) -> Unit = { _, _ -> }
|
||||
actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper)
|
||||
) = namedIrModulePhase(
|
||||
name, description, prerequisite,
|
||||
preconditions=preconditions,
|
||||
postconditions = postconditions,
|
||||
stickyPostconditions = stickyPostconditions,
|
||||
verify = verify,
|
||||
actions = actions,
|
||||
nlevels = 0,
|
||||
lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> {
|
||||
override fun invoke(
|
||||
@@ -222,10 +221,7 @@ fun <Context : CommonBackendContext, Input> unitPhase(
|
||||
context.op()
|
||||
}
|
||||
}
|
||||
) {
|
||||
override val inputDumperVerifier = EmptyDumperVerifier<Context, Input>()
|
||||
override val outputDumperVerifier = EmptyDumperVerifier<Context, Unit>()
|
||||
}
|
||||
) {}
|
||||
|
||||
fun <Context : CommonBackendContext, Input> unitSink() = object : CompilerPhase<Context, Input, Unit> {
|
||||
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {}
|
||||
|
||||
+2
@@ -19,6 +19,8 @@ class PhaseConfig(
|
||||
val verbose: Set<AnyNamedPhase> = emptySet(),
|
||||
val toDumpStateBefore: Set<AnyNamedPhase> = emptySet(),
|
||||
val toDumpStateAfter: Set<AnyNamedPhase> = emptySet(),
|
||||
val dumpToDirectory: String? = null,
|
||||
val dumpOnlyFqName: String? = null,
|
||||
val toValidateStateBefore: Set<AnyNamedPhase> = emptySet(),
|
||||
val toValidateStateAfter: Set<AnyNamedPhase> = emptySet(),
|
||||
val namesOfElementsExcludedFromDumping: Set<String> = emptySet(),
|
||||
|
||||
@@ -33,12 +33,14 @@ private fun validationCallback(context: JsIrBackendContext, module: IrModuleFrag
|
||||
module.accept(CheckDeclarationParentsVisitor, null)
|
||||
}
|
||||
|
||||
val validationAction = makeVerifyAction(::validationCallback)
|
||||
|
||||
private fun makeJsModulePhase(
|
||||
lowering: (JsIrBackendContext) -> FileLoweringPass,
|
||||
name: String,
|
||||
description: String,
|
||||
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(
|
||||
op: (JsIrBackendContext, IrModuleFragment) -> Unit,
|
||||
@@ -49,7 +51,7 @@ private fun makeCustomJsModulePhase(
|
||||
name,
|
||||
description,
|
||||
prerequisite,
|
||||
verify = ::validationCallback,
|
||||
actions = setOf(defaultDumper, validationAction),
|
||||
nlevels = 0,
|
||||
lower = object : SameTypeCompilerPhase<JsIrBackendContext, IrModuleFragment> {
|
||||
override fun invoke(
|
||||
|
||||
@@ -19,7 +19,7 @@ fun compile(
|
||||
project: Project,
|
||||
files: List<KtFile>,
|
||||
configuration: CompilerConfiguration,
|
||||
phaseConfig: PhaseConfig = PhaseConfig(jsPhases),
|
||||
phaseConfig: PhaseConfig,
|
||||
immediateDependencies: List<KlibModuleRef>,
|
||||
allDependencies: List<KlibModuleRef>,
|
||||
friendDependencies: List<KlibModuleRef>,
|
||||
|
||||
+2
@@ -15,6 +15,8 @@ where advanced options include:
|
||||
-Xcoroutines={enable|warn|error}
|
||||
Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
|
||||
-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
|
||||
-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
|
||||
|
||||
+2
@@ -79,6 +79,8 @@ where advanced options include:
|
||||
-Xcoroutines={enable|warn|error}
|
||||
Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
|
||||
-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
|
||||
-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
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
package org.jetbrains.kotlin.js.test
|
||||
|
||||
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.compile
|
||||
import org.jetbrains.kotlin.ir.backend.js.generateKLib
|
||||
@@ -90,11 +90,28 @@ abstract class BasicIrBoxTest(
|
||||
}
|
||||
|
||||
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(
|
||||
project = config.project,
|
||||
files = filesToCompile,
|
||||
configuration = config.configuration,
|
||||
phaseConfig = config.configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jsPhases),
|
||||
phaseConfig = phaseConfig,
|
||||
immediateDependencies = dependencies,
|
||||
allDependencies = allDependencies,
|
||||
friendDependencies = emptyList(),
|
||||
|
||||
Reference in New Issue
Block a user