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.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid 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.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
@@ -404,3 +405,15 @@ fun IrFile.getKtFile(): KtFile? =
fun IrType.isInlineClassType(): Boolean = fun IrType.isInlineClassType(): Boolean =
erasedUpperBound.isInline 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.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.parentClassId import org.jetbrains.kotlin.backend.jvm.codegen.parentClassId
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder 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.irArrayOf
import org.jetbrains.kotlin.backend.jvm.ir.needsAccessor import org.jetbrains.kotlin.backend.jvm.ir.needsAccessor
import org.jetbrains.kotlin.backend.jvm.lower.FunctionReferenceLowering.Companion.calculateOwner 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.codegen.optimization.nullCheck.usesLocalExceptParameterNullCheck
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* 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.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.* 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.JavaDescriptorVisibilities
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name 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) return loadCompiledInlineFunction(containerId, signature.asmMethod, isSuspend, hasMangledReturnType, context.state)
.node.usesLocalExceptParameterNullCheck(localIndex) .node.usesLocalExceptParameterNullCheck(localIndex)
} }
return hasChild { it is IrGetValue && it.symbol == valueParameters[index].symbol }
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
} }
// Assuming that the only functions that take PROPERTY_REFERENCE_FOR_DELEGATE-kind references are getValue, // 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>() private val usesPropertyParameterCache = ConcurrentHashMap<IrSymbol, Boolean>()
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
if (!expression.symbol.owner.isInline) { // Don't generate entries in `$$delegatedProperties` if they won't be used for anything. This is only possible
// Can't optimize if the function can start using the reference later. // for inline functions, since for non-inline ones we need to provide some non-null value, and if they're not
// TODO: optimize if callee is in the same file? this requires removing the null check from it, // in the same file, they can start using it without forcing a recompilation of this file.
// or at least providing *some* non-null fake property value. if (!expression.symbol.owner.isInline) return super.visitCall(expression)
return super.visitCall(expression)
}
for (index in expression.symbol.owner.valueParameters.indices) { for (index in expression.symbol.owner.valueParameters.indices) {
val value = expression.getValueArgument(index) val value = expression.getValueArgument(index)
if (value is IrCallableReference<*> && value.origin == IrStatementOrigin.PROPERTY_REFERENCE_FOR_DELEGATE) { if (value is IrCallableReference<*> && value.origin == IrStatementOrigin.PROPERTY_REFERENCE_FOR_DELEGATE) {
if (!usesPropertyParameterCache.getOrPut(expression.symbol) { expression.symbol.owner.usesParameter(index) }) { 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)) 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.ir.*
import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder 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.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.isReadOfCrossinline import org.jetbrains.kotlin.backend.jvm.codegen.isReadOfCrossinline
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator 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.COROUTINE_LABEL_FIELD_NAME
import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_FUNCTION_COMPLETION_PARAMETER_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 { private fun IrFunction.capturesCrossinline(): Boolean {
var result = false val parents = parents.toSet()
accept(object : IrElementVisitorVoid { return hasChild { it is IrGetValue && it.isReadOfCrossinline() && it.symbol.owner.parent in parents }
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
} }
internal abstract class SuspendLoweringUtils(protected val context: JvmBackendContext) { internal abstract class SuspendLoweringUtils(protected val context: JvmBackendContext) {