JVM_IR: make codegen a phase
This commit is contained in:
+5
-30
@@ -6,14 +6,12 @@
|
|||||||
package org.jetbrains.kotlin.backend.jvm
|
package org.jetbrains.kotlin.backend.jvm
|
||||||
|
|
||||||
import org.jetbrains.kotlin.analyzer.hasJdkCapability
|
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.IrGenerationExtension
|
||||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl
|
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl
|
||||||
import org.jetbrains.kotlin.backend.common.ir.BuiltinSymbolsBase
|
import org.jetbrains.kotlin.backend.common.ir.BuiltinSymbolsBase
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
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.ir.getKtFile
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
||||||
import org.jetbrains.kotlin.codegen.CodegenFactory
|
import org.jetbrains.kotlin.codegen.CodegenFactory
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
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.JvmIrLinker
|
||||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc
|
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc
|
||||||
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
|
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.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
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.Psi2IrConfiguration
|
||||||
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl
|
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.psi2ir.generators.generateTypicalIrProviderList
|
||||||
import org.jetbrains.kotlin.resolve.CleanableBindingContext
|
import org.jetbrains.kotlin.resolve.CleanableBindingContext
|
||||||
|
|
||||||
@@ -182,37 +178,16 @@ open class JvmIrCodegenFactory(
|
|||||||
fun doGenerateFilesInternal(input: JvmIrBackendInput) {
|
fun doGenerateFilesInternal(input: JvmIrBackendInput) {
|
||||||
val (state, irModuleFragment, symbolTable, phaseConfig, irProviders, extensions, backendExtension, notifyCodegenStart) = input
|
val (state, irModuleFragment, symbolTable, phaseConfig, irProviders, extensions, backendExtension, notifyCodegenStart) = input
|
||||||
val context = JvmBackendContext(
|
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. */
|
/* JvmBackendContext creates new unbound symbols, have to resolve them. */
|
||||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||||
|
|
||||||
context.state.factory.registerSourceFiles(irModuleFragment.files.map(IrFile::getKtFile))
|
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
|
// TODO: split classes into groups connected by inline calls; call this after every group
|
||||||
// and clear `JvmBackendContext.classCodegens`
|
// and clear `JvmBackendContext.classCodegens`
|
||||||
state.afterIndependentPart()
|
state.afterIndependentPart()
|
||||||
@@ -224,7 +199,7 @@ open class JvmIrCodegenFactory(
|
|||||||
symbolTable: SymbolTable,
|
symbolTable: SymbolTable,
|
||||||
extensions: JvmGeneratorExtensionsImpl,
|
extensions: JvmGeneratorExtensionsImpl,
|
||||||
backendExtension: JvmBackendExtension,
|
backendExtension: JvmBackendExtension,
|
||||||
notifyCodegenStart: () -> Unit
|
notifyCodegenStart: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val irProviders = configureBuiltInsAndGenerateIrProvidersInFrontendIRMode(irModuleFragment, symbolTable, extensions)
|
val irProviders = configureBuiltInsAndGenerateIrProvidersInFrontendIRMode(irModuleFragment, symbolTable, extensions)
|
||||||
doGenerateFilesInternal(
|
doGenerateFilesInternal(
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ class JvmBackendContext(
|
|||||||
val phaseConfig: PhaseConfig,
|
val phaseConfig: PhaseConfig,
|
||||||
val generatorExtensions: JvmGeneratorExtensions,
|
val generatorExtensions: JvmGeneratorExtensions,
|
||||||
val backendExtension: JvmBackendExtension,
|
val backendExtension: JvmBackendExtension,
|
||||||
|
val notifyCodegenStart: () -> Unit,
|
||||||
) : CommonBackendContext {
|
) : CommonBackendContext {
|
||||||
// If the JVM fqname of a class differs from what is implied by its parent, e.g. if it's a file class
|
// 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.
|
// 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.loops.forLoopsPhase
|
||||||
import org.jetbrains.kotlin.backend.common.lower.optimizations.foldConstantLoweringPhase
|
import org.jetbrains.kotlin.backend.common.lower.optimizations.foldConstantLoweringPhase
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.*
|
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.codegen.shouldContainSuspendMarkers
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.*
|
import org.jetbrains.kotlin.backend.jvm.lower.*
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
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.PatchDeclarationParentsVisitor
|
||||||
import org.jetbrains.kotlin.ir.util.isAnonymousObject
|
import org.jetbrains.kotlin.ir.util.isAnonymousObject
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
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.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
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'"
|
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(
|
private val jvmFilePhases = listOf(
|
||||||
typeAliasAnnotationMethodsPhase,
|
typeAliasAnnotationMethodsPhase,
|
||||||
stripTypeAliasDeclarationsPhase,
|
stripTypeAliasDeclarationsPhase,
|
||||||
@@ -379,11 +417,10 @@ private val jvmFilePhases = listOf(
|
|||||||
makePatchParentsPhase(3)
|
makePatchParentsPhase(3)
|
||||||
)
|
)
|
||||||
|
|
||||||
val jvmPhases = NamedCompilerPhase(
|
private val jvmLoweringPhases = NamedCompilerPhase(
|
||||||
name = "IrLowering",
|
name = "IrLowering",
|
||||||
description = "IR lowering",
|
description = "IR lowering",
|
||||||
nlevels = 1,
|
nlevels = 1,
|
||||||
actions = setOf(defaultDumper, validationAction),
|
|
||||||
lower = validateIrBeforeLowering then
|
lower = validateIrBeforeLowering then
|
||||||
processOptionalAnnotationsPhase then
|
processOptionalAnnotationsPhase then
|
||||||
expectDeclarationsRemovingPhase then
|
expectDeclarationsRemovingPhase then
|
||||||
@@ -398,9 +435,25 @@ val jvmPhases = NamedCompilerPhase(
|
|||||||
validateIrAfterLowering
|
validateIrAfterLowering
|
||||||
)
|
)
|
||||||
|
|
||||||
class JvmLower(val context: JvmBackendContext) {
|
// Generate multifile facades first, to compute and store JVM signatures of const properties which are later used
|
||||||
fun lower(irModuleFragment: IrModuleFragment) {
|
// when serializing metadata in the multifile parts.
|
||||||
// TODO run lowering passes as callbacks in bottom-up visitor
|
// TODO: consider dividing codegen itself into separate phases (bytecode generation, metadata serialization) to avoid this
|
||||||
jvmPhases.invokeToplevel(context.phaseConfig, context, irModuleFragment)
|
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,
|
irProviders,
|
||||||
extensions,
|
extensions,
|
||||||
FirJvmBackendExtension(inputArtifact.session, components),
|
FirJvmBackendExtension(inputArtifact.session, components),
|
||||||
) {}
|
notifyCodegenStart = {},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user