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.CommonBackendContext
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
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.IrInstanceInitializerCall
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.IrSetFieldImpl
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
object SYNTHESIZED_INIT_BLOCK : IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK")
open class InitializersLowering(
context: CommonBackendContext
) : InitializersLoweringBase(context) {
open class InitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) {
override fun lower(irClass: IrClass) {
val nonStaticDeclarations = getDeclarationsWithNonStaticInitializers(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 {
val instanceInitializerStatements = extractInitializers(irClass) {
(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>) {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
val copiedBlock =
IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, null, instanceInitializerStatements)
.copy(irClass) as IrBlock
return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, copiedBlock.statements)
}
override fun visitSimpleFunction(declaration: IrSimpleFunction) = declaration
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression =
IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, instanceInitializerStatements)
.deepCopyWithSymbols(currentScope!!.scope.getLocalDeclarationParent())
})
}
}
abstract class InitializersLoweringBase(val context: CommonBackendContext) : ClassLoweringPass {
protected fun handleDeclaration(irClass: IrClass, declaration: IrDeclaration): IrStatement? = when (declaration) {
is IrField -> handleField(irClass, declaration)
is IrAnonymousInitializer -> handleAnonymousInitializer(declaration)
else -> null
}
protected fun extractInitializers(irClass: IrClass, filter: (IrDeclaration) -> Boolean) =
irClass.declarations.filter(filter).mapNotNull {
when (it) {
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? {
val irFieldInitializer = declaration.initializer?.expression ?: return null
private fun handleField(irClass: IrClass, declaration: IrField): IrStatement? =
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 =
if (!declaration.isStatic) // TODO isStaticField
IrGetValueImpl(
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)
private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement =
with(declaration) {
IrBlockImpl(startOffset, endOffset, context.irBuiltIns.unitType, SYNTHESIZED_INIT_BLOCK, body.statements)
}
}
@@ -6,74 +6,46 @@
package org.jetbrains.kotlin.backend.jvm.lower
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.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.expressions.IrSetField
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
class StaticInitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) {
override fun lower(irClass: IrClass) {
val staticDeclarations = getDeclarationsWithStaticInitializers(irClass)
val staticInitializerStatements = staticDeclarations.mapNotNull { handleDeclaration(irClass, it) }
val staticInitializerStatements = extractInitializers(irClass) {
(it is IrField && it.isStatic) || (it is IrAnonymousInitializer && it.isStatic)
}.toMutableList()
if (staticInitializerStatements.isNotEmpty()) {
createStaticInitializationMethod(irClass, staticInitializerStatements)
val anonymousInitializers = staticDeclarations.filterTo(hashSetOf()) { it is IrAnonymousInitializer }
irClass.declarations.removeAll(anonymousInitializers)
staticInitializerStatements.sortBy {
when ((it as? IrSetField)?.symbol?.owner?.origin) {
IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY -> 1
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 {
val clinitName = Name.special("<clinit>")
}