JVM IR: move non-private const properties from multifile part to facade

This commit is contained in:
Alexander Udalov
2019-07-24 14:53:46 +02:00
parent f01b0f6467
commit 49b534e894
3 changed files with 81 additions and 20 deletions
@@ -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.phaser.PhaseConfig
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.state.GenerationState
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
@@ -85,18 +86,26 @@ object JvmBackendFacade {
errorHandler.reportException(e, null)
}
for (irFile in irModuleFragment.files) {
try {
for (loweredClass in irFile.declarations) {
if (loweredClass !is IrClass) {
throw AssertionError("File-level declaration should be IrClass after JvmLower, got: " + loweredClass.render())
}
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
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
}
}
}
@@ -5,8 +5,10 @@
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.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.lower.InitializersLowering
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
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.irReturn
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.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.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
internal val generateMultifileFacadesPhase = namedIrModulePhase(
@@ -44,7 +54,9 @@ internal val generateMultifileFacadesPhase = namedIrModulePhase(
context: JvmBackendContext,
input: 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()
return input
}
@@ -71,7 +83,11 @@ internal class MultifileFacadeFileEntry(
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) ->
val fileEntry = MultifileFacadeFileEntry(jvmClassName, partClasses.map(IrClass::fileParent))
val file = IrFileImpl(fileEntry, EmptyPackageFragmentDescriptor(module, jvmClassName.packageFqName))
@@ -87,6 +103,8 @@ private fun generateMultifileFacades(module: ModuleDescriptor, context: JvmBacke
for (partClass in partClasses) {
context.multifileFacadeForPart[partClass.attributeOwnerId as IrClass] = jvmClassName
moveFieldsOfConstProperties(partClass, facadeClass, movedFields)
for (member in partClass.declarations) {
member.createMultifileDelegateIfNeeded(context, facadeClass)
}
@@ -95,6 +113,28 @@ private fun generateMultifileFacades(module: ModuleDescriptor, context: JvmBacke
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) {
if (this !is IrFunction ||
Visibilities.isPrivate(visibility) ||
@@ -135,3 +175,18 @@ private fun IrFunction.computeFunctionForCall(): IrFunction {
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)
}
}
}
@@ -16,13 +16,10 @@ import a.OK
fun box(): String {
val okRef = ::OK
// TODO: see KT-10892
// val annotations = okRef.annotations
// val numAnnotations = annotations.size
// if (numAnnotations != 1) {
// throw AssertionError("Failed, annotations: $annotations")
// }
val annotations = okRef.annotations
if (annotations.size != 1) {
throw AssertionError("Failed, annotations: $annotations")
}
val result = okRef.get()
return result
return okRef.get()
}