IR: refactor InitializersLoweringBase and descendants

This commit is contained in:
pyos
2019-11-23 13:56:03 +01:00
committed by Alexander Udalov
parent a6f8859a49
commit 2ebe269448
2 changed files with 62 additions and 113 deletions
@@ -7,10 +7,9 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
@@ -18,73 +17,51 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
object SYNTHESIZED_INIT_BLOCK : IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK") object SYNTHESIZED_INIT_BLOCK : IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK")
open class InitializersLowering( open class InitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) {
context: CommonBackendContext
) : InitializersLoweringBase(context) {
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
val nonStaticDeclarations = getDeclarationsWithNonStaticInitializers(irClass) val instanceInitializerStatements = extractInitializers(irClass) {
val instanceInitializerStatements = nonStaticDeclarations.mapNotNull { handleDeclaration(irClass, it) }
transformInstanceInitializerCallsInConstructors(irClass, instanceInitializerStatements)
val anonymousInitializers = nonStaticDeclarations.filterTo(hashSetOf()) { it is IrAnonymousInitializer }
irClass.declarations.removeAll(anonymousInitializers)
}
private fun getDeclarationsWithNonStaticInitializers(irClass: IrClass): List<IrDeclaration> =
irClass.declarations.filter {
(it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic) (it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic)
} }
irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
// Only transform constructors of current class.
override fun visitClassNew(declaration: IrClass) = declaration
private fun transformInstanceInitializerCallsInConstructors(irClass: IrClass, instanceInitializerStatements: List<IrStatement>) { override fun visitSimpleFunction(declaration: IrSimpleFunction) = declaration
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression { override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression =
val copiedBlock = IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, instanceInitializerStatements)
IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, null, instanceInitializerStatements) .deepCopyWithSymbols(currentScope!!.scope.getLocalDeclarationParent())
.copy(irClass) as IrBlock
return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, copiedBlock.statements)
}
}) })
} }
} }
abstract class InitializersLoweringBase(val context: CommonBackendContext) : ClassLoweringPass { abstract class InitializersLoweringBase(val context: CommonBackendContext) : ClassLoweringPass {
protected fun handleDeclaration(irClass: IrClass, declaration: IrDeclaration): IrStatement? = when (declaration) { protected fun extractInitializers(irClass: IrClass, filter: (IrDeclaration) -> Boolean) =
is IrField -> handleField(irClass, declaration) irClass.declarations.filter(filter).mapNotNull {
is IrAnonymousInitializer -> handleAnonymousInitializer(declaration) when (it) {
else -> null is IrField -> handleField(irClass, it)
} is IrAnonymousInitializer -> handleAnonymousInitializer(it)
else -> null
}
}.also {
irClass.declarations.removeAll { it is IrAnonymousInitializer && filter(it) }
}
private fun handleField(irClass: IrClass, declaration: IrField): IrStatement? { private fun handleField(irClass: IrClass, declaration: IrField): IrStatement? =
val irFieldInitializer = declaration.initializer?.expression ?: return null declaration.initializer?.run {
val receiver = if (!declaration.isStatic) // TODO isStaticField
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol)
else
null
IrSetFieldImpl(startOffset, endOffset, declaration.symbol, receiver, expression, context.irBuiltIns.unitType)
}
val receiver = private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement =
if (!declaration.isStatic) // TODO isStaticField with(declaration) {
IrGetValueImpl( IrBlockImpl(startOffset, endOffset, context.irBuiltIns.unitType, SYNTHESIZED_INIT_BLOCK, body.statements)
irFieldInitializer.startOffset, irFieldInitializer.endOffset, }
irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol
)
else null
return IrSetFieldImpl(
irFieldInitializer.startOffset, irFieldInitializer.endOffset,
declaration.symbol,
receiver,
irFieldInitializer,
context.irBuiltIns.unitType,
null, null
)
}
private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement = IrBlockImpl(
declaration.startOffset, declaration.endOffset,
context.irBuiltIns.unitType,
SYNTHESIZED_INIT_BLOCK,
declaration.body.statements
)
protected fun IrStatement.copy(containingDeclaration: IrDeclarationParent): IrStatement = deepCopyWithSymbols(containingDeclaration)
} }
@@ -6,74 +6,46 @@
package org.jetbrains.kotlin.backend.jvm.lower package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.ir.SetDeclarationsParentVisitor
import org.jetbrains.kotlin.backend.common.lower.InitializersLoweringBase import org.jetbrains.kotlin.backend.common.lower.InitializersLoweringBase
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.ir.expressions.IrSetField
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
class StaticInitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) { class StaticInitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) {
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
val staticDeclarations = getDeclarationsWithStaticInitializers(irClass) val staticInitializerStatements = extractInitializers(irClass) {
val staticInitializerStatements = staticDeclarations.mapNotNull { handleDeclaration(irClass, it) } (it is IrField && it.isStatic) || (it is IrAnonymousInitializer && it.isStatic)
}.toMutableList()
if (staticInitializerStatements.isNotEmpty()) { if (staticInitializerStatements.isNotEmpty()) {
createStaticInitializationMethod(irClass, staticInitializerStatements) staticInitializerStatements.sortBy {
when ((it as? IrSetField)?.symbol?.owner?.origin) {
val anonymousInitializers = staticDeclarations.filterTo(hashSetOf()) { it is IrAnonymousInitializer } IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY -> 1
irClass.declarations.removeAll(anonymousInitializers) IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES -> 2
IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE -> 3
else -> 4
}
}
irClass.addFunction {
startOffset = irClass.startOffset
endOffset = irClass.endOffset
name = clinitName
// TODO: mark as synthesized
origin = JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER
returnType = context.irBuiltIns.unitType
}.apply {
body = IrBlockBodyImpl(irClass.startOffset, irClass.endOffset, staticInitializerStatements)
.deepCopyWithSymbols(this)
}
} }
} }
private fun getDeclarationsWithStaticInitializers(irClass: IrClass): List<IrDeclaration> =
// Hardcoded order of initializers
(irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY } +
irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES } +
irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE } +
irClass.declarations.filter {
(it is IrField && it.isStatic && it.origin !in listOf(
IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY,
IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES,
IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE
)) || (it is IrAnonymousInitializer && it.isStatic)
})
private fun createStaticInitializationMethod(irClass: IrClass, staticInitializerStatements: List<IrStatement>) {
// TODO: mark as synthesized
val staticInitializerDescriptor = WrappedSimpleFunctionDescriptor()
val staticInitializer = IrFunctionImpl(
irClass.startOffset,
irClass.endOffset,
JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER,
IrSimpleFunctionSymbolImpl(staticInitializerDescriptor),
clinitName,
Visibilities.PUBLIC,
Modality.FINAL,
returnType = context.irBuiltIns.unitType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false,
isExpect = false,
isFakeOverride = false,
isOperator = false
).apply {
staticInitializerDescriptor.bind(this)
body = IrBlockBodyImpl(irClass.startOffset, irClass.endOffset,
staticInitializerStatements.map { it.copy(irClass) })
accept(SetDeclarationsParentVisitor, this)
// Should come after SetDeclarationParentVisitor, because it sets staticInitializer's own parent to itself.
parent = irClass
}
irClass.declarations.add(staticInitializer)
}
companion object { companion object {
val clinitName = Name.special("<clinit>") val clinitName = Name.special("<clinit>")
} }