JVM_IR: create temporaries for complex super constructor arguments

As for SAM wrappers, the bytecode sequence

    new A
    dup
    new B
    dup
    invokespecial B.<init>
    invokespecial A.<init>

breaks the inliner, so instead we do

    new B
    dup
    invokespecial B.<init>
    store x
    new A
    dup
    load x
    invokespecial A.<init>
This commit is contained in:
pyos
2019-10-22 10:03:58 +02:00
committed by max-kammerer
parent 42f75b3247
commit 5d8aac456f
6 changed files with 53 additions and 11 deletions
@@ -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 `<init>`, as the inliner gets confused if
// an argument to `<init>` 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)
}
@@ -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()
@@ -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)
@@ -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)
@@ -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)
@@ -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)