From 6f9f437f151be66e209c6ff8115064c3b3f6f012 Mon Sep 17 00:00:00 2001 From: pyos Date: Fri, 9 Oct 2020 14:00:33 +0200 Subject: [PATCH] IR: refuse to copy classes in InitializersLowering --- .../common/lower/InitializersLowering.kt | 37 +++++++------------ .../kotlin/ir/backend/js/JsLoweringPhases.kt | 4 +- .../kotlin/backend/wasm/WasmLoweringPhases.kt | 2 +- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt index 586997ae6f7..aa55bf7c980 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt @@ -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) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 68a7a970e8f..96b5ac3c756 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -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( diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt index 3a2ad262d04..d661effa94a 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt @@ -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(