JVM IR: Optimize static property references (KT-36975)

This commit is contained in:
Steven Schäfer
2020-09-07 17:16:23 +02:00
committed by Alexander Udalov
parent 669fda6b77
commit 4792be2522
9 changed files with 107 additions and 18 deletions
@@ -53,6 +53,6 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
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 FIELD_FOR_STATIC_LAMBDA_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_STATIC_LAMBDA_INSTANCE")
object FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE")
object ABSTRACT_BRIDGE_STUB : IrDeclarationOriginImpl("ABSTRACT_BRIDGE_STUB")
}
@@ -315,7 +315,7 @@ private val jvmFilePhases = listOf(
returnableBlocksPhase,
localDeclarationsPhase,
jvmLocalClassExtractionPhase,
staticLambdaPhase,
staticCallableReferencePhase,
jvmDefaultConstructorPhase,
@@ -13,8 +13,8 @@ import org.jetbrains.kotlin.backend.jvm.lower.hasAssertionsDisabledField
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor
@@ -270,7 +270,7 @@ abstract class ClassCodegen protected constructor(
if (field.origin != JvmLoweredDeclarationOrigin.CONTINUATION_CLASS_RESULT_FIELD) {
val skipNullabilityAnnotations =
flags and (Opcodes.ACC_SYNTHETIC or Opcodes.ACC_ENUM) != 0 ||
field.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_STATIC_LAMBDA_INSTANCE
field.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE
object : AnnotationCodegen(this@ClassCodegen, context, skipNullabilityAnnotations) {
override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor {
return fv.visitAnnotation(descr, visible)
@@ -35,21 +35,21 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.*
internal val staticLambdaPhase = makeIrFilePhase(
::StaticLambdaLowering,
name = "StaticLambdaPhase",
internal val staticCallableReferencePhase = makeIrFilePhase(
::StaticCallableReferenceLowering,
name = "StaticCallableReferencePhase",
description = "Turn static callable references into singletons"
)
class StaticLambdaLowering(val backendContext: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoid() {
private val staticLambdaFields = HashMap<IrClass, IrField>()
class StaticCallableReferenceLowering(val backendContext: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoid() {
private val staticInstanceFields = HashMap<IrClass, IrField>()
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid()
override fun visitClass(declaration: IrClass): IrStatement {
declaration.transformChildrenVoid()
if (declaration.isSyntheticSingleton) {
declaration.declarations += getFieldForStaticLambdaInstance(declaration).also { field ->
declaration.declarations += getFieldForStaticCallableReferenceInstance(declaration).also { field ->
field.initializer = backendContext.createIrBuilder(field.symbol).run {
irExprBody(irCall(declaration.primaryConstructor!!))
}
@@ -58,17 +58,17 @@ class StaticLambdaLowering(val backendContext: JvmBackendContext) : FileLowering
return declaration
}
private fun getFieldForStaticLambdaInstance(lambdaClass: IrClass): IrField =
staticLambdaFields.getOrPut(lambdaClass) {
private fun getFieldForStaticCallableReferenceInstance(irClass: IrClass): IrField =
staticInstanceFields.getOrPut(irClass) {
backendContext.irFactory.buildField {
name = Name.identifier(JvmAbi.INSTANCE_FIELD)
type = lambdaClass.defaultType
origin = JvmLoweredDeclarationOrigin.FIELD_FOR_STATIC_LAMBDA_INSTANCE
type = irClass.defaultType
origin = JvmLoweredDeclarationOrigin.FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE
isFinal = true
isStatic = true
visibility = DescriptorVisibilities.PUBLIC
}.apply {
parent = lambdaClass
parent = irClass
}
}
@@ -77,14 +77,16 @@ class StaticLambdaLowering(val backendContext: JvmBackendContext) : FileLowering
if (!constructor.constructedClass.isSyntheticSingleton)
return super.visitConstructorCall(expression)
val instanceField = getFieldForStaticLambdaInstance(constructor.constructedClass)
val instanceField = getFieldForStaticCallableReferenceInstance(constructor.constructedClass)
return IrGetFieldImpl(expression.startOffset, expression.endOffset, instanceField.symbol, expression.type)
}
// Recognize callable references with no value or type arguments. The only type arguments in Kotlin stem from usages of
// reified type parameters, which we unfortunately don't record as parameters so we have to check the body of the class.
private val IrClass.isSyntheticSingleton: Boolean
get() = (origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL || origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL)
get() = (origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL
|| origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|| origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE)
&& primaryConstructor!!.valueParameters.isEmpty()
&& !containsReifiedTypeParameters