[JVM_IR] Optimize properties delegated to const val
We can omit `get` call to delegated property and inline constant value directly. If we are not going to do that, we can get a runtime exception because all usages of const property will be inlined and the property itself will be dropped. #KT-63567 Fixed #KT-63580 Fixed
This commit is contained in:
+12
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||
import org.jetbrains.kotlin.ir.util.shallowCopyOrNull
|
||||
import org.jetbrains.kotlin.ir.util.statements
|
||||
|
||||
internal val IrSimpleFunction.returnsResultOfStdlibCall: Boolean
|
||||
@@ -68,3 +69,14 @@ internal fun IrProperty.getSingletonOrConstantForOptimizableDelegatedProperty():
|
||||
fun IrProperty.isJvmOptimizableDelegate(): Boolean =
|
||||
isDelegated && !isFakeOverride && backingField != null && // fast path
|
||||
(getPropertyReferenceForOptimizableDelegatedProperty() != null || getSingletonOrConstantForOptimizableDelegatedProperty() != null)
|
||||
|
||||
internal val IrMemberAccessExpression<*>.constInitializer: IrExpression?
|
||||
get() {
|
||||
if (this !is IrPropertyReference) return null
|
||||
val constPropertyField = if (field == null) {
|
||||
symbol.owner.takeIf { it.isConst }?.backingField
|
||||
} else {
|
||||
field!!.owner.takeIf { it.isFinal && it.isStatic }
|
||||
}
|
||||
return constPropertyField?.initializer?.expression?.shallowCopyOrNull()
|
||||
}
|
||||
+8
-3
@@ -41,9 +41,14 @@ private class PropertyReferenceDelegationLowering(val context: JvmBackendContext
|
||||
}
|
||||
|
||||
private class PropertyReferenceDelegationTransformer(val context: JvmBackendContext) : IrElementTransformerVoid() {
|
||||
private fun IrSimpleFunction.accessorBody(delegate: IrPropertyReference, receiverFieldOrExpression: IrStatement?) =
|
||||
private fun IrSimpleFunction.accessorBody(delegate: IrPropertyReference, receiverFieldOrExpression: IrStatement?): IrBody =
|
||||
context.createIrBuilder(symbol, startOffset, endOffset).run {
|
||||
val value = valueParameters.singleOrNull()?.let(::irGet)
|
||||
val isGetter = value == null
|
||||
if (isGetter) {
|
||||
delegate.constInitializer?.let { return@run irExprBody(it) }
|
||||
}
|
||||
|
||||
var boundReceiver = when (receiverFieldOrExpression) {
|
||||
null -> null
|
||||
is IrField -> irGetField(dispatchReceiverParameter?.let(::irGet), receiverFieldOrExpression)
|
||||
@@ -54,7 +59,7 @@ private class PropertyReferenceDelegationTransformer(val context: JvmBackendCont
|
||||
val unboundReceiver = extensionReceiverParameter ?: dispatchReceiverParameter
|
||||
val field = delegate.field?.owner
|
||||
val access = if (field == null) {
|
||||
val accessor = if (value == null) delegate.getter!! else delegate.setter!!
|
||||
val accessor = if (isGetter) delegate.getter!! else delegate.setter!!
|
||||
irCall(accessor).apply {
|
||||
// This has the same assumptions about receivers as `PropertyReferenceLowering.propertyReferenceKindFor`:
|
||||
// only one receiver can be bound, and if the property has both, the extension receiver cannot be bound.
|
||||
@@ -72,7 +77,7 @@ private class PropertyReferenceDelegationTransformer(val context: JvmBackendCont
|
||||
}
|
||||
} else {
|
||||
val receiver = if (field.isStatic) null else boundReceiver ?: irGet(unboundReceiver!!)
|
||||
if (value == null) irGetField(receiver, field) else irSetField(receiver, field, value)
|
||||
if (isGetter) irGetField(receiver, field) else irSetField(receiver, field, value!!)
|
||||
}
|
||||
irExprBody(access)
|
||||
}
|
||||
|
||||
-11
@@ -67,17 +67,6 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
|
||||
private val IrMemberAccessExpression<*>.field: IrFieldSymbol?
|
||||
get() = (this as? IrPropertyReference)?.field
|
||||
|
||||
private val IrMemberAccessExpression<*>.constInitializer: IrExpression?
|
||||
get() {
|
||||
if (this !is IrPropertyReference) return null
|
||||
val constPropertyField = if (field == null) {
|
||||
symbol.owner.takeIf { it.isConst }?.backingField
|
||||
} else {
|
||||
field!!.owner.takeIf { it.isFinal && it.isStatic }
|
||||
}
|
||||
return constPropertyField?.initializer?.expression?.shallowCopyOrNull()
|
||||
}
|
||||
|
||||
private val arrayItemGetter =
|
||||
context.ir.symbols.array.owner.functions.single { it.name.asString() == "get" }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user