JVM IR: move non-private const properties from multifile part to facade
This commit is contained in:
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
|||||||
import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations
|
import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations
|
||||||
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.jvm.codegen.ClassCodegen
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
|
||||||
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
|
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||||
@@ -85,18 +86,26 @@ object JvmBackendFacade {
|
|||||||
errorHandler.reportException(e, null)
|
errorHandler.reportException(e, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (irFile in irModuleFragment.files) {
|
for (generateMultifileFacade in listOf(true, false)) {
|
||||||
try {
|
for (irFile in irModuleFragment.files) {
|
||||||
for (loweredClass in irFile.declarations) {
|
// Generate multifile facades first, to compute and store JVM signatures of const properties which are later used
|
||||||
if (loweredClass !is IrClass) {
|
// when serializing metadata in the multifile parts.
|
||||||
throw AssertionError("File-level declaration should be IrClass after JvmLower, got: " + loweredClass.render())
|
// 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
|
||||||
|
|
||||||
ClassCodegen.generate(loweredClass, context)
|
try {
|
||||||
|
for (loweredClass in irFile.declarations) {
|
||||||
|
if (loweredClass !is IrClass) {
|
||||||
|
throw AssertionError("File-level declaration should be IrClass after JvmLower, got: " + loweredClass.render())
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassCodegen.generate(loweredClass, context)
|
||||||
|
}
|
||||||
|
state.afterIndependentPart()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
errorHandler.reportException(e, null) // TODO ktFile.virtualFile.url
|
||||||
}
|
}
|
||||||
state.afterIndependentPart()
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
errorHandler.reportException(e, null) // TODO ktFile.virtualFile.url
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-2
@@ -5,8 +5,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.jvm.lower
|
package org.jetbrains.kotlin.backend.jvm.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.deepCopyWithWrappedDescriptors
|
import org.jetbrains.kotlin.backend.common.deepCopyWithWrappedDescriptors
|
||||||
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower
|
||||||
import org.jetbrains.kotlin.backend.common.lower.InitializersLowering
|
import org.jetbrains.kotlin.backend.common.lower.InitializersLowering
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||||
@@ -28,9 +30,17 @@ import org.jetbrains.kotlin.ir.builders.irCall
|
|||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrGetField
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
|
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
|
|
||||||
internal val generateMultifileFacadesPhase = namedIrModulePhase(
|
internal val generateMultifileFacadesPhase = namedIrModulePhase(
|
||||||
@@ -44,7 +54,9 @@ internal val generateMultifileFacadesPhase = namedIrModulePhase(
|
|||||||
context: JvmBackendContext,
|
context: JvmBackendContext,
|
||||||
input: IrModuleFragment
|
input: IrModuleFragment
|
||||||
): IrModuleFragment {
|
): IrModuleFragment {
|
||||||
input.files.addAll(generateMultifileFacades(input.descriptor, context))
|
val movedFields = mutableMapOf<IrFieldSymbol, IrFieldSymbol>()
|
||||||
|
input.files.addAll(generateMultifileFacades(input.descriptor, context, movedFields))
|
||||||
|
UpdateFieldCallSites(movedFields).lower(input)
|
||||||
context.multifileFacadesToAdd.clear()
|
context.multifileFacadesToAdd.clear()
|
||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
@@ -71,7 +83,11 @@ internal class MultifileFacadeFileEntry(
|
|||||||
error("Multifile facade doesn't support debug info: $className")
|
error("Multifile facade doesn't support debug info: $className")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateMultifileFacades(module: ModuleDescriptor, context: JvmBackendContext): List<IrFile> =
|
private fun generateMultifileFacades(
|
||||||
|
module: ModuleDescriptor,
|
||||||
|
context: JvmBackendContext,
|
||||||
|
movedFields: MutableMap<IrFieldSymbol, IrFieldSymbol>
|
||||||
|
): List<IrFile> =
|
||||||
context.multifileFacadesToAdd.map { (jvmClassName, partClasses) ->
|
context.multifileFacadesToAdd.map { (jvmClassName, partClasses) ->
|
||||||
val fileEntry = MultifileFacadeFileEntry(jvmClassName, partClasses.map(IrClass::fileParent))
|
val fileEntry = MultifileFacadeFileEntry(jvmClassName, partClasses.map(IrClass::fileParent))
|
||||||
val file = IrFileImpl(fileEntry, EmptyPackageFragmentDescriptor(module, jvmClassName.packageFqName))
|
val file = IrFileImpl(fileEntry, EmptyPackageFragmentDescriptor(module, jvmClassName.packageFqName))
|
||||||
@@ -87,6 +103,8 @@ private fun generateMultifileFacades(module: ModuleDescriptor, context: JvmBacke
|
|||||||
for (partClass in partClasses) {
|
for (partClass in partClasses) {
|
||||||
context.multifileFacadeForPart[partClass.attributeOwnerId as IrClass] = jvmClassName
|
context.multifileFacadeForPart[partClass.attributeOwnerId as IrClass] = jvmClassName
|
||||||
|
|
||||||
|
moveFieldsOfConstProperties(partClass, facadeClass, movedFields)
|
||||||
|
|
||||||
for (member in partClass.declarations) {
|
for (member in partClass.declarations) {
|
||||||
member.createMultifileDelegateIfNeeded(context, facadeClass)
|
member.createMultifileDelegateIfNeeded(context, facadeClass)
|
||||||
}
|
}
|
||||||
@@ -95,6 +113,28 @@ private fun generateMultifileFacades(module: ModuleDescriptor, context: JvmBacke
|
|||||||
file
|
file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun moveFieldsOfConstProperties(
|
||||||
|
partClass: IrClass,
|
||||||
|
facadeClass: IrClass,
|
||||||
|
movedFields: MutableMap<IrFieldSymbol, IrFieldSymbol>
|
||||||
|
) {
|
||||||
|
partClass.declarations.transformFlat { member ->
|
||||||
|
if (member is IrField && member.shouldMoveToFacade()) {
|
||||||
|
val field = member.deepCopyWithSymbols(facadeClass).also {
|
||||||
|
(it as IrFieldImpl).metadata = member.metadata
|
||||||
|
}
|
||||||
|
facadeClass.declarations.add(field)
|
||||||
|
movedFields[member.symbol] = field.symbol
|
||||||
|
emptyList()
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrField.shouldMoveToFacade(): Boolean {
|
||||||
|
val property = correspondingPropertySymbol?.owner
|
||||||
|
return property != null && property.isConst && !Visibilities.isPrivate(visibility)
|
||||||
|
}
|
||||||
|
|
||||||
private fun IrDeclaration.createMultifileDelegateIfNeeded(context: JvmBackendContext, facadeClass: IrClass) {
|
private fun IrDeclaration.createMultifileDelegateIfNeeded(context: JvmBackendContext, facadeClass: IrClass) {
|
||||||
if (this !is IrFunction ||
|
if (this !is IrFunction ||
|
||||||
Visibilities.isPrivate(visibility) ||
|
Visibilities.isPrivate(visibility) ||
|
||||||
@@ -135,3 +175,18 @@ private fun IrFunction.computeFunctionForCall(): IrFunction {
|
|||||||
else -> error("Property accessor must be getter or setter: ${dump()}")
|
else -> error("Property accessor must be getter or setter: ${dump()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class UpdateFieldCallSites(
|
||||||
|
private val movedFields: Map<IrFieldSymbol, IrFieldSymbol>
|
||||||
|
) : FileLoweringPass, IrElementTransformerVoid() {
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
irFile.transformChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGetField(expression: IrGetField): IrExpression {
|
||||||
|
val newField = movedFields[expression.symbol] ?: return super.visitGetField(expression)
|
||||||
|
return expression.run {
|
||||||
|
IrGetFieldImpl(startOffset, endOffset, newField, type, receiver, origin, superQualifierSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+5
-8
@@ -16,13 +16,10 @@ import a.OK
|
|||||||
fun box(): String {
|
fun box(): String {
|
||||||
val okRef = ::OK
|
val okRef = ::OK
|
||||||
|
|
||||||
// TODO: see KT-10892
|
val annotations = okRef.annotations
|
||||||
// val annotations = okRef.annotations
|
if (annotations.size != 1) {
|
||||||
// val numAnnotations = annotations.size
|
throw AssertionError("Failed, annotations: $annotations")
|
||||||
// if (numAnnotations != 1) {
|
}
|
||||||
// throw AssertionError("Failed, annotations: $annotations")
|
|
||||||
// }
|
|
||||||
|
|
||||||
val result = okRef.get()
|
return okRef.get()
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user