diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt index da8e6636c7e..aef3282ada0 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities import org.jetbrains.kotlin.load.java.JvmAbi @@ -404,3 +405,15 @@ fun IrFile.getKtFile(): KtFile? = fun IrType.isInlineClassType(): Boolean = erasedUpperBound.isInline + +inline fun IrElement.hasChild(crossinline block: (IrElement) -> Boolean): Boolean { + var result = false + acceptChildren(object : IrElementVisitorVoid { + override fun visitElement(element: IrElement) = when { + result -> Unit + block(element) -> result = true + else -> element.acceptChildren(this, null) + } + }, null) + return result +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt index 52de0ea7582..366220baa94 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.parentClassId import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder +import org.jetbrains.kotlin.backend.jvm.ir.hasChild import org.jetbrains.kotlin.backend.jvm.ir.irArrayOf import org.jetbrains.kotlin.backend.jvm.ir.needsAccessor import org.jetbrains.kotlin.backend.jvm.lower.FunctionReferenceLowering.Companion.calculateOwner @@ -28,7 +29,6 @@ import org.jetbrains.kotlin.codegen.inline.loadCompiledInlineFunction import org.jetbrains.kotlin.codegen.optimization.nullCheck.usesLocalExceptParameterNullCheck import org.jetbrains.kotlin.descriptors.DescriptorVisibilities 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.* @@ -47,7 +47,6 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name @@ -274,17 +273,7 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem return loadCompiledInlineFunction(containerId, signature.asmMethod, isSuspend, hasMangledReturnType, context.state) .node.usesLocalExceptParameterNullCheck(localIndex) } - - var result = false - accept(object : IrElementVisitorVoid { - override fun visitElement(element: IrElement) = - if (result) Unit else element.acceptChildren(this, null) - - override fun visitGetValue(expression: IrGetValue) { - if (expression.symbol == valueParameters[index].symbol) result = true - } - }, null) - return result + return hasChild { it is IrGetValue && it.symbol == valueParameters[index].symbol } } // Assuming that the only functions that take PROPERTY_REFERENCE_FOR_DELEGATE-kind references are getValue, @@ -292,18 +281,14 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem private val usesPropertyParameterCache = ConcurrentHashMap() override fun visitCall(expression: IrCall): IrExpression { - if (!expression.symbol.owner.isInline) { - // Can't optimize if the function can start using the reference later. - // TODO: optimize if callee is in the same file? this requires removing the null check from it, - // or at least providing *some* non-null fake property value. - return super.visitCall(expression) - } - + // Don't generate entries in `$$delegatedProperties` if they won't be used for anything. This is only possible + // for inline functions, since for non-inline ones we need to provide some non-null value, and if they're not + // in the same file, they can start using it without forcing a recompilation of this file. + if (!expression.symbol.owner.isInline) return super.visitCall(expression) for (index in expression.symbol.owner.valueParameters.indices) { val value = expression.getValueArgument(index) if (value is IrCallableReference<*> && value.origin == IrStatementOrigin.PROPERTY_REFERENCE_FOR_DELEGATE) { if (!usesPropertyParameterCache.getOrPut(expression.symbol) { expression.symbol.owner.usesParameter(index) }) { - // Don't generate an entry in `$$delegatedProperties`, it won't be used anyway. expression.putValueArgument(index, IrConstImpl.constNull(value.startOffset, value.endOffset, value.type)) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt index 39b15b27585..265e552e536 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt @@ -10,11 +10,13 @@ import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.ir.* import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering 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.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.isReadOfCrossinline import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator +import org.jetbrains.kotlin.backend.jvm.ir.hasChild import org.jetbrains.kotlin.codegen.coroutines.COROUTINE_LABEL_FIELD_NAME import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME @@ -47,25 +49,8 @@ internal val suspendLambdaPhase = makeIrFilePhase( ) private fun IrFunction.capturesCrossinline(): Boolean { - var result = false - accept(object : IrElementVisitorVoid { - override fun visitElement(element: IrElement) { - if (!result) element.acceptChildren(this, null) - } - - override fun visitFunction(declaration: IrFunction) { - functions.add(declaration) - super.visitFunction(declaration) - functions.remove(declaration) - } - - override fun visitGetValue(expression: IrGetValue) { - result = result || (expression.isReadOfCrossinline() && expression.symbol.owner.parent !in functions) - } - - private val functions = mutableSetOf() - }, null) - return result + val parents = parents.toSet() + return hasChild { it is IrGetValue && it.isReadOfCrossinline() && it.symbol.owner.parent in parents } } internal abstract class SuspendLoweringUtils(protected val context: JvmBackendContext) {