JVM_IR: make codegen a phase
This commit is contained in:
+5
-30
@@ -6,14 +6,12 @@
|
||||
package org.jetbrains.kotlin.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.analyzer.hasJdkCapability
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl
|
||||
import org.jetbrains.kotlin.backend.common.ir.BuiltinSymbolsBase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.ClassCodegen
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getKtFile
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
||||
import org.jetbrains.kotlin.codegen.CodegenFactory
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
@@ -25,7 +23,6 @@ import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc
|
||||
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
|
||||
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.declarations.impl.IrFactoryImpl
|
||||
@@ -37,7 +34,6 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
|
||||
import org.jetbrains.kotlin.psi2ir.generators.generateTypicalIrProviderList
|
||||
import org.jetbrains.kotlin.resolve.CleanableBindingContext
|
||||
|
||||
@@ -182,37 +178,16 @@ open class JvmIrCodegenFactory(
|
||||
fun doGenerateFilesInternal(input: JvmIrBackendInput) {
|
||||
val (state, irModuleFragment, symbolTable, phaseConfig, irProviders, extensions, backendExtension, notifyCodegenStart) = input
|
||||
val context = JvmBackendContext(
|
||||
state, irModuleFragment.irBuiltins, irModuleFragment, symbolTable, phaseConfig, extensions, backendExtension
|
||||
state, irModuleFragment.irBuiltins, irModuleFragment, symbolTable, phaseConfig, extensions, backendExtension,
|
||||
notifyCodegenStart
|
||||
)
|
||||
/* JvmBackendContext creates new unbound symbols, have to resolve them. */
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
|
||||
context.state.factory.registerSourceFiles(irModuleFragment.files.map(IrFile::getKtFile))
|
||||
|
||||
JvmLower(context).lower(irModuleFragment)
|
||||
jvmPhases.invokeToplevel(phaseConfig, context, irModuleFragment)
|
||||
|
||||
notifyCodegenStart()
|
||||
|
||||
for (generateMultifileFacade in listOf(true, false)) {
|
||||
for (irFile in irModuleFragment.files) {
|
||||
// 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
|
||||
val isMultifileFacade = irFile.fileEntry is MultifileFacadeFileEntry
|
||||
if (isMultifileFacade != generateMultifileFacade) continue
|
||||
|
||||
try {
|
||||
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()
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
CodegenUtil.reportBackendException(e, "code generation", irFile.fileEntry.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: split classes into groups connected by inline calls; call this after every group
|
||||
// and clear `JvmBackendContext.classCodegens`
|
||||
state.afterIndependentPart()
|
||||
@@ -224,7 +199,7 @@ open class JvmIrCodegenFactory(
|
||||
symbolTable: SymbolTable,
|
||||
extensions: JvmGeneratorExtensionsImpl,
|
||||
backendExtension: JvmBackendExtension,
|
||||
notifyCodegenStart: () -> Unit
|
||||
notifyCodegenStart: () -> Unit = {}
|
||||
) {
|
||||
val irProviders = configureBuiltInsAndGenerateIrProvidersInFrontendIRMode(irModuleFragment, symbolTable, extensions)
|
||||
doGenerateFilesInternal(
|
||||
|
||||
@@ -52,6 +52,7 @@ class JvmBackendContext(
|
||||
val phaseConfig: PhaseConfig,
|
||||
val generatorExtensions: JvmGeneratorExtensions,
|
||||
val backendExtension: JvmBackendExtension,
|
||||
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.
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase
|
||||
import org.jetbrains.kotlin.backend.common.lower.optimizations.foldConstantLoweringPhase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.*
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.ClassCodegen
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.shouldContainSuspendMarkers
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.*
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
@@ -21,6 +22,7 @@ import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.util.PatchDeclarationParentsVisitor
|
||||
import org.jetbrains.kotlin.ir.util.isAnonymousObject
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
@@ -273,6 +275,42 @@ private val kotlinNothingValueExceptionPhase = makeIrFilePhase<CommonBackendCont
|
||||
description = "Throw proper exception for calls returning value of type 'kotlin.Nothing'"
|
||||
)
|
||||
|
||||
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"
|
||||
return performByIrFile(
|
||||
name = "CodegenByIrFile$suffix",
|
||||
description = "Code generation by IrFile$descriptionSuffix",
|
||||
lower = listOf(
|
||||
makeIrFilePhase(
|
||||
{ context ->
|
||||
object : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
val isMultifileFacade = irFile.fileEntry is MultifileFacadeFileEntry
|
||||
if (isMultifileFacade != generateMultifileFacade) return
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
name = "Codegen$suffix",
|
||||
description = "Code generation"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private val jvmFilePhases = listOf(
|
||||
typeAliasAnnotationMethodsPhase,
|
||||
stripTypeAliasDeclarationsPhase,
|
||||
@@ -379,11 +417,10 @@ private val jvmFilePhases = listOf(
|
||||
makePatchParentsPhase(3)
|
||||
)
|
||||
|
||||
val jvmPhases = NamedCompilerPhase(
|
||||
private val jvmLoweringPhases = NamedCompilerPhase(
|
||||
name = "IrLowering",
|
||||
description = "IR lowering",
|
||||
nlevels = 1,
|
||||
actions = setOf(defaultDumper, validationAction),
|
||||
lower = validateIrBeforeLowering then
|
||||
processOptionalAnnotationsPhase then
|
||||
expectDeclarationsRemovingPhase then
|
||||
@@ -398,9 +435,25 @@ val jvmPhases = NamedCompilerPhase(
|
||||
validateIrAfterLowering
|
||||
)
|
||||
|
||||
class JvmLower(val context: JvmBackendContext) {
|
||||
fun lower(irModuleFragment: IrModuleFragment) {
|
||||
// TODO run lowering passes as callbacks in bottom-up visitor
|
||||
jvmPhases.invokeToplevel(context.phaseConfig, context, irModuleFragment)
|
||||
}
|
||||
}
|
||||
// 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(
|
||||
name = "Codegen",
|
||||
description = "Code generation",
|
||||
nlevels = 1,
|
||||
lower = codegenPhase(generateMultifileFacade = true) then
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
+2
-1
@@ -87,7 +87,8 @@ class Fir2IrResultsConverter(
|
||||
irProviders,
|
||||
extensions,
|
||||
FirJvmBackendExtension(inputArtifact.session, components),
|
||||
) {}
|
||||
notifyCodegenStart = {},
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user