From 7206c06d26241eef42819e027ed119da05c09670 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 3 Dec 2021 12:06:42 +0300 Subject: [PATCH] IR KT-50039 don't initialize outer 'this' in delegating constructor --- .../FirBlackBoxCodegenTestGenerated.java | 6 ++++++ .../common/lower/InnerClassesLowering.kt | 16 ++++++++++++++-- .../objectExtendsInnerDefaultArgument.kt | 5 +++++ ...jectExtendsInnerWithDelegatingConstructor.kt | 17 +++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++++++ .../codegen/IrBlackBoxCodegenTestGenerated.java | 6 ++++++ .../codegen/LightAnalysisModeTestGenerated.java | 5 +++++ .../js/test/JsCodegenBoxTestGenerated.java | 6 ++++++ .../js/test/ir/IrJsCodegenBoxTestGenerated.java | 6 ++++++ .../IrCodegenBoxWasmTestGenerated.java | 5 +++++ .../NativeExtBlackBoxTestGenerated.java | 6 ++++++ 11 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index b1259d246d9..f9d457caa16 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -22317,6 +22317,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt"); } + @Test + @TestMetadata("objectExtendsInnerWithDelegatingConstructor.kt") + public void testObjectExtendsInnerWithDelegatingConstructor() throws Exception { + runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt"); + } + @Test @TestMetadata("objectExtendsLocalCaptureInSuperCall.kt") public void testObjectExtendsLocalCaptureInSuperCall() throws Exception { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InnerClassesLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InnerClassesLowering.kt index be52e39a710..9d4ae11b2da 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InnerClassesLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InnerClassesLowering.kt @@ -68,8 +68,11 @@ class InnerClassesLowering(val context: BackendContext, private val innerClasses if (blockBody !is IrBlockBody) throw AssertionError("Unexpected constructor body: ${irConstructor.body}") loweredConstructor.body = context.irFactory.createBlockBody(blockBody.startOffset, blockBody.endOffset) { - context.createIrBuilder(irConstructor.symbol, irConstructor.startOffset, irConstructor.endOffset).apply { - statements.add(0, irSetField(irGet(irClass.thisReceiver!!), parentThisField, irGet(outerThisParameter))) + + if (irConstructor.shouldInitializeOuterThis()) { + context.createIrBuilder(irConstructor.symbol, irConstructor.startOffset, irConstructor.endOffset).apply { + statements.add(0, irSetField(irGet(irClass.thisReceiver!!), parentThisField, irGet(outerThisParameter))) + } } statements.addAll(blockBody.statements) @@ -90,6 +93,15 @@ class InnerClassesLowering(val context: BackendContext, private val innerClasses return loweredConstructor } + private fun IrConstructor.shouldInitializeOuterThis(): Boolean { + val irBlockBody = body as? IrBlockBody ?: return false + // Constructors are either delegating to a constructor of super class (and initializing an instance of this class), + // or delegating to a constructor of this class. + // Don't initialize outer 'this' in constructor delegating to this, + // otherwise final 'this$0' field will be initialized twice (in delegating constructor and in original constructor), + // which is legal, but causes a performance regression on JVM (KT-50039). + return irBlockBody.statements.any { it is IrInstanceInitializerCall } + } } private fun InnerClassesSupport.primaryConstructorParameterMap(originalConstructor: IrConstructor): Map { diff --git a/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerDefaultArgument.kt b/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerDefaultArgument.kt index c94d6ab49ca..4fc962997ee 100644 --- a/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerDefaultArgument.kt +++ b/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerDefaultArgument.kt @@ -10,3 +10,8 @@ class A { } fun box() = A().box() + +// CHECK_BYTECODE_TEXT +// 1 PUTFIELD A\$Inner\.this\$0 : LA; +// ^ A$Inner.this$0 SHOULD be written in primary constructor of A$Inner, +// and SHOULD NOT be written in corresponding default arguments stub. diff --git a/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt b/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt new file mode 100644 index 00000000000..7571d881de3 --- /dev/null +++ b/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt @@ -0,0 +1,17 @@ +class Outer(val outer: String) { + open inner class Inner(val inner: String) { + constructor() : this("K") + + fun test() = outer + inner + } + + fun obj(): Inner = + object : Inner() {} +} + +fun box() = Outer("O").obj().test() + +// CHECK_BYTECODE_TEXT +// 1 PUTFIELD Outer\$Inner\.this\$0 : LOuter; +// ^ Outer$Inner.this$0 SHOULD be written in primary constructor of Outer$Inner, +// and SHOULD NOT be written in delegating constructor. diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index aad0a31df26..075b1ec50a0 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -21945,6 +21945,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt"); } + @Test + @TestMetadata("objectExtendsInnerWithDelegatingConstructor.kt") + public void testObjectExtendsInnerWithDelegatingConstructor() throws Exception { + runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt"); + } + @Test @TestMetadata("objectExtendsLocalCaptureInSuperCall.kt") public void testObjectExtendsLocalCaptureInSuperCall() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index f1e234dcfe8..c5a2f0a595f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -22317,6 +22317,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt"); } + @Test + @TestMetadata("objectExtendsInnerWithDelegatingConstructor.kt") + public void testObjectExtendsInnerWithDelegatingConstructor() throws Exception { + runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt"); + } + @Test @TestMetadata("objectExtendsLocalCaptureInSuperCall.kt") public void testObjectExtendsLocalCaptureInSuperCall() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 8868580ba07..e2a65fc09f9 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -18360,6 +18360,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt"); } + @TestMetadata("objectExtendsInnerWithDelegatingConstructor.kt") + public void testObjectExtendsInnerWithDelegatingConstructor() throws Exception { + runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt"); + } + @TestMetadata("objectExtendsLocalCaptureInSuperCall.kt") public void testObjectExtendsLocalCaptureInSuperCall() throws Exception { runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsLocalCaptureInSuperCall.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index ed9a76c7e8e..25a21609070 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -17507,6 +17507,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt"); } + @Test + @TestMetadata("objectExtendsInnerWithDelegatingConstructor.kt") + public void testObjectExtendsInnerWithDelegatingConstructor() throws Exception { + runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt"); + } + @Test @TestMetadata("objectExtendsLocalCaptureInSuperCall.kt") public void testObjectExtendsLocalCaptureInSuperCall() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index 40b96108d06..da8d8a83759 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -17471,6 +17471,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt"); } + @Test + @TestMetadata("objectExtendsInnerWithDelegatingConstructor.kt") + public void testObjectExtendsInnerWithDelegatingConstructor() throws Exception { + runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt"); + } + @Test @TestMetadata("objectExtendsLocalCaptureInSuperCall.kt") public void testObjectExtendsLocalCaptureInSuperCall() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 1b3f9b1fb48..97bdc01b427 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -14807,6 +14807,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt"); } + @TestMetadata("objectExtendsInnerWithDelegatingConstructor.kt") + public void testObjectExtendsInnerWithDelegatingConstructor() throws Exception { + runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt"); + } + @TestMetadata("objectExtendsLocalCaptureInSuperCall.kt") public void testObjectExtendsLocalCaptureInSuperCall() throws Exception { runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsLocalCaptureInSuperCall.kt"); diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java index fae708bd9ff..452ce4e0606 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java @@ -18390,6 +18390,12 @@ public class NativeExtBlackBoxTestGenerated extends AbstractNativeBlackBoxTest { runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt"); } + @Test + @TestMetadata("objectExtendsInnerWithDelegatingConstructor.kt") + public void testObjectExtendsInnerWithDelegatingConstructor() throws Exception { + runTest("compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsInnerWithDelegatingConstructor.kt"); + } + @Test @TestMetadata("objectExtendsLocalCaptureInSuperCall.kt") public void testObjectExtendsLocalCaptureInSuperCall() throws Exception {