JVM_IR: do not inline reads of constructor arguments into accessors

This commit is contained in:
pyos
2021-07-27 12:40:48 +02:00
committed by Alexander Udalov
parent 2baf344f5f
commit e9b177352c
10 changed files with 59 additions and 10 deletions

View File

@@ -13316,6 +13316,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnotherWithSideEffects.kt");
}
@Test
@TestMetadata("delegateToConstructorParameter.kt")
public void testDelegateToConstructorParameter() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToConstructorParameter.kt");
}
@Test
@TestMetadata("delegateToGenericJavaProperty.kt")
public void testDelegateToGenericJavaProperty() throws Exception {

View File

@@ -59,7 +59,7 @@ val IrDeclaration.parentsWithSelf: Sequence<IrDeclarationParent>
get() = generateSequence(this as? IrDeclarationParent) { (it as? IrDeclaration)?.parent }
val IrDeclaration.parents: Sequence<IrDeclarationParent>
get() = parentsWithSelf.drop(1)
get() = generateSequence(parent) { (it as? IrDeclaration)?.parent }
object BOUND_VALUE_PARAMETER : IrDeclarationOriginImpl("BOUND_VALUE_PARAMETER")

View File

@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.fileParent
@@ -85,14 +86,16 @@ private class PropertyReferenceDelegationTransformer(val context: JvmBackendCont
private val IrStatement.isStdlibCall: Boolean
get() = this is IrCall && symbol.owner.getPackageFragment()?.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME
// Constants, object accesses, reads of immutable variables, and reads of immutable properties in the same file
// don't need to be cached in a field; reads of mutable properties have to be as we should ignore further assignments
// to those, and immutable properties in other files might become mutable without breaking ABI.
private fun IrExpression.canInline(currentFile: IrFile): Boolean = when (this) {
is IrGetValue -> !symbol.owner.let { it is IrVariable && it.isVar }
is IrGetField -> symbol.owner.let { it.isFinal && it.fileParent == currentFile } && receiver?.canInline(currentFile) != false
is IrCall -> symbol.owner.let { it.isFinalDefaultValGetter && it.fileParent == currentFile } &&
dispatchReceiver?.canInline(currentFile) != false && extensionReceiver?.canInline(currentFile) != false
// Some receivers don't need to be stored in fields and can be reevaluated every time an accessor is called:
private fun IrExpression.canInline(visibleScopes: Set<IrDeclarationParent>): Boolean = when (this) {
// Reads of immutable variables are stable, but value parameters of the constructor are not in scope:
is IrGetValue -> symbol.owner.let { !(it is IrVariable && it.isVar) && it.parent in visibleScopes }
// Reads of final fields of stable values are stable, but fields in other files can become non-final:
is IrGetField -> symbol.owner.let { it.isFinal && it.fileParent in visibleScopes } && receiver?.canInline(visibleScopes) != false
// Same applies to reads of properties with default getters, but non-final properties may be overridden by `var`s:
is IrCall -> symbol.owner.let { it.isFinalDefaultValGetter && it.fileParent in visibleScopes } &&
dispatchReceiver?.canInline(visibleScopes) != false && extensionReceiver?.canInline(visibleScopes) != false
// Constants and singleton object accesses are always stable:
else -> isTrivial()
}
@@ -134,7 +137,7 @@ private class PropertyReferenceDelegationTransformer(val context: JvmBackendCont
val receiver = (delegate.dispatchReceiver ?: delegate.extensionReceiver)
?.transform(this@PropertyReferenceDelegationTransformer, null)
backingField = receiver?.takeIf { !it.canInline(fileParent) }?.let {
backingField = receiver?.takeIf { !it.canInline(parents.toSet()) }?.let {
context.irFactory.buildField {
updateFrom(oldField)
name = Name.identifier("${this@transform.name}\$receiver")

View File

@@ -0,0 +1,8 @@
// WITH_RUNTIME
class C(val x: String)
class D(c: C) {
val x by c::x
}
fun box(): String = D(C("OK")).x

View File

@@ -13256,6 +13256,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnotherWithSideEffects.kt");
}
@Test
@TestMetadata("delegateToConstructorParameter.kt")
public void testDelegateToConstructorParameter() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToConstructorParameter.kt");
}
@Test
@TestMetadata("delegateToGenericJavaProperty.kt")
public void testDelegateToGenericJavaProperty() throws Exception {

View File

@@ -13316,6 +13316,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnotherWithSideEffects.kt");
}
@Test
@TestMetadata("delegateToConstructorParameter.kt")
public void testDelegateToConstructorParameter() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToConstructorParameter.kt");
}
@Test
@TestMetadata("delegateToGenericJavaProperty.kt")
public void testDelegateToGenericJavaProperty() throws Exception {

View File

@@ -10775,6 +10775,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnotherWithSideEffects.kt");
}
@TestMetadata("delegateToConstructorParameter.kt")
public void testDelegateToConstructorParameter() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToConstructorParameter.kt");
}
@TestMetadata("delegateToGenericJavaProperty.kt")
public void testDelegateToGenericJavaProperty() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToGenericJavaProperty.kt");

View File

@@ -9584,6 +9584,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnotherWithSideEffects.kt");
}
@TestMetadata("delegateToConstructorParameter.kt")
public void testDelegateToConstructorParameter() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToConstructorParameter.kt");
}
@TestMetadata("delegateToOpenProperty.kt")
public void testDelegateToOpenProperty() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToOpenProperty.kt");

View File

@@ -8990,6 +8990,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnotherWithSideEffects.kt");
}
@TestMetadata("delegateToConstructorParameter.kt")
public void testDelegateToConstructorParameter() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToConstructorParameter.kt");
}
@TestMetadata("delegateToOpenProperty.kt")
public void testDelegateToOpenProperty() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToOpenProperty.kt");

View File

@@ -8990,6 +8990,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToAnotherWithSideEffects.kt");
}
@TestMetadata("delegateToConstructorParameter.kt")
public void testDelegateToConstructorParameter() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToConstructorParameter.kt");
}
@TestMetadata("delegateToOpenProperty.kt")
public void testDelegateToOpenProperty() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/delegateToOpenProperty.kt");