From 5d8aac456f9362becc3e7d1cf3ac9522ecca13bd Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 22 Oct 2019 10:03:58 +0200 Subject: [PATCH] JVM_IR: create temporaries for complex super constructor arguments As for SAM wrappers, the bytecode sequence new A dup new B dup invokespecial B. invokespecial A. breaks the inliner, so instead we do new B dup invokespecial B. store x new A dup load x invokespecial A. --- ...AnonymousObjectSuperConstructorLowering.kt | 31 ++++++++++++------- .../superConstructorWithObjectParameter.kt | 13 ++++++++ .../BlackBoxInlineCodegenTestGenerated.java | 5 +++ ...otlinAgainstInlineKotlinTestGenerated.java | 5 +++ .../IrBlackBoxInlineCodegenTestGenerated.java | 5 +++ ...otlinAgainstInlineKotlinTestGenerated.java | 5 +++ 6 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/anonymousObject/superConstructorWithObjectParameter.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AnonymousObjectSuperConstructorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AnonymousObjectSuperConstructorLowering.kt index 5e50ac58ab4..74b6e60790a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AnonymousObjectSuperConstructorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AnonymousObjectSuperConstructorLowering.kt @@ -6,17 +6,21 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter +import org.jetbrains.kotlin.ir.builders.irCallConstructor +import org.jetbrains.kotlin.ir.builders.irGet +import org.jetbrains.kotlin.ir.builders.irTemporary import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.util.transform -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid internal val anonymousObjectSuperConstructorPhase = makeIrFilePhase( ::AnonymousObjectSuperConstructorLowering, @@ -49,7 +53,8 @@ internal val anonymousObjectSuperConstructorPhase = makeIrFilePhase( // attempts to read them from fields, causing a bytecode validation error. // // (TODO fix the inliner instead. Then keep this code for one more version for backwards compatibility.) -private class AnonymousObjectSuperConstructorLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { +private class AnonymousObjectSuperConstructorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), + FileLoweringPass { override fun lower(irFile: IrFile) { irFile.transformChildrenVoid() } @@ -100,14 +105,18 @@ private class AnonymousObjectSuperConstructorLowering(val context: JvmBackendCon } } - expression.statements[expression.statements.size - 1] = IrConstructorCallImpl.fromSymbolOwner( - objectConstructorCall.startOffset, objectConstructorCall.endOffset, objectConstructorCall.type, - objectConstructorCall.symbol, objectConstructorCall.origin - ).apply { - for (i in 0 until objectConstructorCall.valueArgumentsCount) - putValueArgument(i, objectConstructorCall.getValueArgument(i)) - for ((i, argument) in newArguments.withIndex()) - putValueArgument(i + objectConstructorCall.valueArgumentsCount, argument) + context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run { + expression.statements[expression.statements.size - 1] = irBlock(objectConstructorCall) { + +irCallConstructor(objectConstructor.symbol, listOf()).apply { + for (i in 0 until objectConstructorCall.valueArgumentsCount) + putValueArgument(i, objectConstructorCall.getValueArgument(i)) + // Avoid complex expressions between `new` and ``, as the inliner gets confused if + // an argument to `` is an anonymous object. Put them in variables instead. + // See KT-21781 for an example; in short, it looks like `object : S({ ... })` in an inline function. + for ((i, argument) in newArguments.withIndex()) + putValueArgument(i + objectConstructorCall.valueArgumentsCount, irGet(irTemporary(argument))) + } + } } return super.visitBlock(expression) } diff --git a/compiler/testData/codegen/boxInline/anonymousObject/superConstructorWithObjectParameter.kt b/compiler/testData/codegen/boxInline/anonymousObject/superConstructorWithObjectParameter.kt new file mode 100644 index 00000000000..3a23da3fecf --- /dev/null +++ b/compiler/testData/codegen/boxInline/anonymousObject/superConstructorWithObjectParameter.kt @@ -0,0 +1,13 @@ +// IGNORE_BACKEND: JVM +// IGNORE_BACKEND_MULTI_MODULE: JVM +// FILE: 1.kt +package test + +open class C(val x: () -> String) + +inline fun f(crossinline g: () -> String) = object : C({ g() }) {} + +// FILE: 2.kt +import test.* + +fun box(): String = f { "OK" }.x() diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index eb4d411046c..b8ac448f4f2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -271,6 +271,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo runTest("compiler/testData/codegen/boxInline/anonymousObject/sam.kt"); } + @TestMetadata("superConstructorWithObjectParameter.kt") + public void testSuperConstructorWithObjectParameter() throws Exception { + runTest("compiler/testData/codegen/boxInline/anonymousObject/superConstructorWithObjectParameter.kt"); + } + @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index ebcb5cbcb80..33687e76b36 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -271,6 +271,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi runTest("compiler/testData/codegen/boxInline/anonymousObject/sam.kt"); } + @TestMetadata("superConstructorWithObjectParameter.kt") + public void testSuperConstructorWithObjectParameter() throws Exception { + runTest("compiler/testData/codegen/boxInline/anonymousObject/superConstructorWithObjectParameter.kt"); + } + @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 9d6106b28aa..c01d81a29a3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -271,6 +271,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli runTest("compiler/testData/codegen/boxInline/anonymousObject/sam.kt"); } + @TestMetadata("superConstructorWithObjectParameter.kt") + public void testSuperConstructorWithObjectParameter() throws Exception { + runTest("compiler/testData/codegen/boxInline/anonymousObject/superConstructorWithObjectParameter.kt"); + } + @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index c355e776ee2..26951f6b541 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -271,6 +271,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC runTest("compiler/testData/codegen/boxInline/anonymousObject/sam.kt"); } + @TestMetadata("superConstructorWithObjectParameter.kt") + public void testSuperConstructorWithObjectParameter() throws Exception { + runTest("compiler/testData/codegen/boxInline/anonymousObject/superConstructorWithObjectParameter.kt"); + } + @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)