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
|
package org.jetbrains.kotlin.backend.jvm.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
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.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
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.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
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.expressions.impl.IrGetValueImpl
|
||||||
import org.jetbrains.kotlin.ir.util.transform
|
import org.jetbrains.kotlin.ir.util.transform
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
|
|
||||||
internal val anonymousObjectSuperConstructorPhase = makeIrFilePhase(
|
internal val anonymousObjectSuperConstructorPhase = makeIrFilePhase(
|
||||||
::AnonymousObjectSuperConstructorLowering,
|
::AnonymousObjectSuperConstructorLowering,
|
||||||
@@ -49,7 +53,8 @@ internal val anonymousObjectSuperConstructorPhase = makeIrFilePhase(
|
|||||||
// attempts to read them from fields, causing a bytecode validation error.
|
// 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.)
|
// (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) {
|
override fun lower(irFile: IrFile) {
|
||||||
irFile.transformChildrenVoid()
|
irFile.transformChildrenVoid()
|
||||||
}
|
}
|
||||||
@@ -100,14 +105,18 @@ private class AnonymousObjectSuperConstructorLowering(val context: JvmBackendCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expression.statements[expression.statements.size - 1] = IrConstructorCallImpl.fromSymbolOwner(
|
context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run {
|
||||||
objectConstructorCall.startOffset, objectConstructorCall.endOffset, objectConstructorCall.type,
|
expression.statements[expression.statements.size - 1] = irBlock(objectConstructorCall) {
|
||||||
objectConstructorCall.symbol, objectConstructorCall.origin
|
+irCallConstructor(objectConstructor.symbol, listOf()).apply {
|
||||||
).apply {
|
for (i in 0 until objectConstructorCall.valueArgumentsCount)
|
||||||
for (i in 0 until objectConstructorCall.valueArgumentsCount)
|
putValueArgument(i, objectConstructorCall.getValueArgument(i))
|
||||||
putValueArgument(i, objectConstructorCall.getValueArgument(i))
|
// Avoid complex expressions between `new` and `<init>`, as the inliner gets confused if
|
||||||
for ((i, argument) in newArguments.withIndex())
|
// an argument to `<init>` is an anonymous object. Put them in variables instead.
|
||||||
putValueArgument(i + objectConstructorCall.valueArgumentsCount, argument)
|
// 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)
|
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");
|
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")
|
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Generated
+5
@@ -271,6 +271,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
runTest("compiler/testData/codegen/boxInline/anonymousObject/sam.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+5
@@ -271,6 +271,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
|||||||
runTest("compiler/testData/codegen/boxInline/anonymousObject/sam.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Generated
+5
@@ -271,6 +271,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
|||||||
runTest("compiler/testData/codegen/boxInline/anonymousObject/sam.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user