[JVM_IR] Use direct field access to backing fields on current class.
The current backend uses direct field access to the backing field
instead of calling the companion object accessor, which calls
an accessibility bridge, which then gets the field for code such as:
```
class A {
companion object {
val s: String = "OK"
}
// f uses direct access to the A.s backing field.
fun f() = s
}
```
This change does the same for the IR backend.
This commit is contained in:
+1
-1
@@ -43,7 +43,7 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
object FOR_INLINE_STATE_MACHINE_TEMPLATE : IrDeclarationOriginImpl("FOR_INLINE_TEMPLATE")
|
||||
object FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE : IrDeclarationOriginImpl("FOR_INLINE_TEMPLATE_CROSSINLINE")
|
||||
object CONTINUATION_CLASS_RESULT_FIELD: IrDeclarationOriginImpl("CONTINUATION_CLASS_RESULT_FIELD", isSynthetic = true)
|
||||
object COMPANION_PROPERTY_BACKING_FIELD : IrDeclarationOriginImpl("COMPANION_MOVED_PROPERTY_BACKING_FIELD")
|
||||
object COMPANION_PROPERTY_BACKING_FIELD : IrDeclarationOriginImpl("COMPANION_PROPERTY_BACKING_FIELD")
|
||||
object FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE")
|
||||
object ABSTRACT_BRIDGE_STUB : IrDeclarationOriginImpl("ABSTRACT_BRIDGE_STUB")
|
||||
}
|
||||
|
||||
+23
-5
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.requiresMangling
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
@@ -28,10 +29,7 @@ import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.coerceToUnit
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -54,7 +52,9 @@ class JvmPropertiesLowering(private val backendContext: JvmBackendContext) : IrE
|
||||
val property = simpleFunction.correspondingPropertySymbol?.owner ?: return super.visitCall(expression)
|
||||
expression.transformChildrenVoid()
|
||||
|
||||
if (shouldSubstituteAccessorWithField(property, simpleFunction)) {
|
||||
if (shouldSubstituteAccessorWithField(property, simpleFunction) ||
|
||||
isDefaultAccessorForCompanionPropertyBackingFieldOnCurrentClass(property, simpleFunction)
|
||||
) {
|
||||
backendContext.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).apply {
|
||||
return when (simpleFunction) {
|
||||
property.getter -> substituteGetter(property, expression)
|
||||
@@ -67,6 +67,24 @@ class JvmPropertiesLowering(private val backendContext: JvmBackendContext) : IrE
|
||||
return expression
|
||||
}
|
||||
|
||||
private fun isDefaultAccessorForCompanionPropertyBackingFieldOnCurrentClass(
|
||||
property: IrProperty,
|
||||
function: IrSimpleFunction
|
||||
): Boolean {
|
||||
if (function.origin != IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) return false
|
||||
if (property.isLateinit) return false
|
||||
// If this code could end up inlined in another class (either an inline function or an
|
||||
// inlined lambda in an inline function) use the companion object accessor. Otherwise,
|
||||
// we could break binary compatibility if we only recompile the class with the companion
|
||||
// object and change to non-default field accessors. The inlined code would still attempt
|
||||
// to get the backing field which would no longer exist.
|
||||
val inInlineFunctionScope = allScopes.any { scope -> (scope.irElement as? IrFunction)?.isInline ?: false }
|
||||
if (inInlineFunctionScope) return false
|
||||
val backingField = property.resolveFakeOverride()!!.backingField
|
||||
return backingField?.parent == currentClass?.irElement &&
|
||||
backingField?.origin == JvmLoweredDeclarationOrigin.COMPANION_PROPERTY_BACKING_FIELD
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.substituteSetter(irProperty: IrProperty, expression: IrCall): IrExpression =
|
||||
patchReceiver(
|
||||
irSetField(
|
||||
|
||||
Reference in New Issue
Block a user