IR: refuse to copy classes in InitializersLowering

This commit is contained in:
pyos
2020-10-09 14:00:33 +02:00
committed by Alexander Udalov
parent e6c0575d3a
commit 6f9f437f15
3 changed files with 18 additions and 25 deletions
@@ -15,12 +15,12 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.*
object SYNTHESIZED_INIT_BLOCK : IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK")
open class InitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context), BodyLoweringPass {
class InitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context), BodyLoweringPass {
override fun lower(irFile: IrFile) {
runOnFilePostfix(irFile, true)
}
@@ -29,31 +29,22 @@ open class InitializersLowering(context: CommonBackendContext) : InitializersLow
if (container !is IrConstructor) return
val irClass = container.constructedClass
val instanceInitializerStatements = extractInitializers(irClass) {
(it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic)
}
val block = IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, instanceInitializerStatements)
// Check that the initializers contain no local classes. Deep-copying them is a disaster for code size, and liable to break randomly.
block.accept(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) =
element.acceptChildren(this, null)
override fun visitClass(declaration: IrClass) =
throw AssertionError("class in initializer should have been moved out by LocalClassPopupLowering: ${declaration.render()}")
}, null)
container.body?.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, instanceInitializerStatements)
.deepCopyWithSymbols(container).also {
// Handle declarations, copied from initializers
// Otherwise local classes inside them won't get processed.
// Yes, there are such cases - see testData/codegen/box/properties/complexPropertyInitializer.kt
it.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitConstructor(declaration: IrConstructor) {
super.visitConstructor(declaration)
declaration.body?.let { lower(it, declaration) }
}
})
}
}
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression =
block.deepCopyWithSymbols(container)
})
}
}
@@ -61,7 +52,7 @@ open class InitializersLowering(context: CommonBackendContext) : InitializersLow
abstract class InitializersLoweringBase(open val context: CommonBackendContext) {
protected fun extractInitializers(irClass: IrClass, filter: (IrDeclaration) -> Boolean) =
// TODO What about fields that were added by lowerings? e.g. captured outer class or locals?
ArrayList(irClass.declarations).mapNotNull { if (it is IrProperty) it.backingField else it }.filter(filter).mapNotNull {
irClass.declarations.mapNotNull { if (it is IrProperty) it.backingField else it }.filter(filter).mapNotNull {
when (it) {
is IrField -> handleField(irClass, it)
is IrAnonymousInitializer -> handleAnonymousInitializer(it)
@@ -504,7 +504,9 @@ private val initializersLoweringPhase = makeBodyLoweringPhase(
::InitializersLowering,
name = "InitializersLowering",
description = "Merge init block and field initializers into [primary] constructor",
prerequisite = setOf(enumClassConstructorLoweringPhase, primaryConstructorLoweringPhase, annotationConstructorLowering)
prerequisite = setOf(
enumClassConstructorLoweringPhase, primaryConstructorLoweringPhase, annotationConstructorLowering, localClassExtractionPhase
)
)
private val initializersCleanupLoweringPhase = makeDeclarationTransformerPhase(
@@ -228,7 +228,7 @@ private val initializersLoweringPhase = makeWasmModulePhase(
::InitializersLowering,
name = "InitializersLowering",
description = "Merge init block and field initializers into [primary] constructor",
prerequisite = setOf(primaryConstructorLoweringPhase)
prerequisite = setOf(primaryConstructorLoweringPhase, localClassExtractionPhase)
)
private val initializersCleanupLoweringPhase = makeWasmModulePhase(