JVM_IR: extract boolean-valued DFS on IR elements into a helper

This commit is contained in:
pyos
2021-06-21 14:26:17 +02:00
committed by Dmitry Petrov
parent ee4d9a89ea
commit 913ac289ed
3 changed files with 23 additions and 40 deletions
@@ -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
}
@@ -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<IrSymbol, Boolean>()
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))
}
}
@@ -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<IrFunction>()
}, 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) {