JVM IR: move codegen out of the main phases

This is needed in order to be able to invoke lowerings and codegen
separately, for cyclically dependent modules (KT-49575).

A side effect is that the two codegen phases are no longer configurable
via the phaser, i.e. absent in the -Xlist-phases and can't be disabled
or made verbose.
This commit is contained in:
Alexander Udalov
2021-11-16 00:17:34 +01:00
parent f701f04326
commit 5012aeba7c
4 changed files with 31 additions and 40 deletions
@@ -221,22 +221,21 @@ open class JvmIrCodegenFactory(
)
JvmIrSerializerImpl(state.configuration)
else null
val phases = prefixPhases?.then(jvmPhases) ?: jvmPhases
val phases = prefixPhases?.then(jvmLoweringPhases) ?: jvmLoweringPhases
val phaseConfig = customPhaseConfig ?: PhaseConfig(phases)
val context = JvmBackendContext(
state, irModuleFragment.irBuiltins, irModuleFragment, symbolTable, phaseConfig, extensions, backendExtension, irSerializer,
notifyCodegenStart,
)
/* JvmBackendContext creates new unbound symbols, have to resolve them. */
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
context.state.factory.registerSourceFiles(irModuleFragment.files.map(IrFile::getKtFile))
phases.invokeToplevel(
phaseConfig,
context,
irModuleFragment
)
phases.invokeToplevel(phaseConfig, context, irModuleFragment)
notifyCodegenStart()
jvmCodegenPhases.invokeToplevel(phaseConfig, context, irModuleFragment)
// TODO: split classes into groups connected by inline calls; call this after every group
// and clear `JvmBackendContext.classCodegens`
@@ -6,19 +6,16 @@
package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.common.phaser.performByIrFile
import org.jetbrains.kotlin.backend.common.phaser.then
import org.jetbrains.kotlin.backend.jvm.codegen.ClassCodegen
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.render
private val notifyCodegenStartPhase = makeCustomPhase<JvmBackendContext, IrModuleFragment>(
op = { context, _ -> context.notifyCodegenStart() },
name = "NotifyCodegenStart",
description = "Notify time measuring subsystem that code generation is being started",
)
private fun codegenPhase(generateMultifileFacade: Boolean): NamedCompilerPhase<JvmBackendContext, IrModuleFragment> {
val suffix = if (generateMultifileFacade) "MultifileFacades" else "Regular"
val descriptionSuffix = if (generateMultifileFacade) ", multifile facades" else ", regular files"
@@ -28,21 +25,7 @@ private fun codegenPhase(generateMultifileFacade: Boolean): NamedCompilerPhase<J
copyBeforeLowering = false,
lower = listOf(
makeIrFilePhase(
{ context ->
object : FileLoweringPass {
override fun lower(irFile: IrFile) {
val isMultifileFacade = irFile.fileEntry is MultifileFacadeFileEntry
if (isMultifileFacade == generateMultifileFacade) {
for (loweredClass in irFile.declarations) {
if (loweredClass !is IrClass) {
throw AssertionError("File-level declaration should be IrClass after JvmLower, got: " + loweredClass.render())
}
ClassCodegen.getOrCreate(loweredClass, context).generate()
}
}
}
}
},
{ context -> FileCodegen(context, generateMultifileFacade) },
name = "Codegen$suffix",
description = "Code generation"
)
@@ -50,10 +33,24 @@ private fun codegenPhase(generateMultifileFacade: Boolean): NamedCompilerPhase<J
)
}
private class FileCodegen(private val context: JvmBackendContext, private val generateMultifileFacade: Boolean) : FileLoweringPass {
override fun lower(irFile: IrFile) {
val isMultifileFacade = irFile.fileEntry is MultifileFacadeFileEntry
if (isMultifileFacade == generateMultifileFacade) {
for (loweredClass in irFile.declarations) {
if (loweredClass !is IrClass) {
throw AssertionError("File-level declaration should be IrClass after JvmLower, got: " + loweredClass.render())
}
ClassCodegen.getOrCreate(loweredClass, context).generate()
}
}
}
}
// Generate multifile facades first, to compute and store JVM signatures of const properties which are later used
// when serializing metadata in the multifile parts.
// TODO: consider dividing codegen itself into separate phases (bytecode generation, metadata serialization) to avoid this
private val jvmCodegenPhases = NamedCompilerPhase(
internal val jvmCodegenPhases = NamedCompilerPhase(
name = "Codegen",
description = "Code generation",
nlevels = 1,
@@ -61,12 +58,7 @@ private val jvmCodegenPhases = NamedCompilerPhase(
codegenPhase(generateMultifileFacade = false)
)
val jvmPhases = NamedCompilerPhase(
name = "IrBackend",
description = "IR Backend for JVM",
nlevels = 1,
actions = setOf(defaultDumper, validationAction),
lower = jvmLoweringPhases then
notifyCodegenStartPhase then
jvmCodegenPhases
)
// This property is needed to avoid dependencies from "leaf" modules (cli, tests-common-new) on backend.jvm:lower.
// It's used to create PhaseConfig and is the only thing needed from lowerings in the leaf modules.
val jvmPhases: NamedCompilerPhase<JvmBackendContext, IrModuleFragment>
get() = jvmLoweringPhases
@@ -390,6 +390,7 @@ val jvmLoweringPhases = NamedCompilerPhase(
name = "IrLowering",
description = "IR lowering",
nlevels = 1,
actions = setOf(defaultDumper, validationAction),
lower = validateIrBeforeLowering then
processOptionalAnnotationsPhase then
expectDeclarationsRemovingPhase then
@@ -48,7 +48,6 @@ class JvmBackendContext(
val generatorExtensions: JvmGeneratorExtensions,
val backendExtension: JvmBackendExtension,
val irSerializer: JvmIrSerializer?,
val notifyCodegenStart: () -> Unit
) : CommonBackendContext {
// If the JVM fqname of a class differs from what is implied by its parent, e.g. if it's a file class
// annotated with @JvmPackageName, the correct name is recorded here.