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:
+20
-11
@@ -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)
|
||||
}
|
||||
|
||||
+13
@@ -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()
|
||||
+5
@@ -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)
|
||||
|
||||
Generated
+5
@@ -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)
|
||||
|
||||
+5
@@ -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)
|
||||
|
||||
Generated
+5
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user