[JVM_IR] Unify code between fake variables lowerings

#KT-58778 Fixed
This commit is contained in:
Ivan Kylchik
2023-07-09 21:45:16 +02:00
committed by Space Team
parent 1dec9fc675
commit 7fd601b336
3 changed files with 64 additions and 52 deletions
@@ -455,8 +455,8 @@ private val jvmFilePhases = listOf(
replaceNumberToCharCallSitesPhase, replaceNumberToCharCallSitesPhase,
renameFieldsPhase, renameFieldsPhase,
fakeInliningLocalVariablesLowering, fakeLocalVariablesForBytecodeInlinerLowering,
fakeInliningLocalVariablesAfterInlineLowering, fakeLocalVariablesForIrInlinerLowering,
// makePatchParentsPhase() // makePatchParentsPhase()
) )
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
import org.jetbrains.kotlin.backend.jvm.ir.isInlineOnly import org.jetbrains.kotlin.backend.jvm.ir.isInlineOnly
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.createTmpVariable import org.jetbrains.kotlin.ir.builders.createTmpVariable
import org.jetbrains.kotlin.ir.builders.irBlockBody import org.jetbrains.kotlin.ir.builders.irBlockBody
import org.jetbrains.kotlin.ir.builders.irInt import org.jetbrains.kotlin.ir.builders.irInt
@@ -23,35 +24,52 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
internal val fakeInliningLocalVariablesLowering = makeIrFilePhase( internal val fakeLocalVariablesForBytecodeInlinerLowering = makeIrFilePhase(
::FakeInliningLocalVariablesLowering, ::FakeLocalVariablesForBytecodeInlinerLowering,
name = "FakeInliningLocalVariablesLowering", name = "FakeLocalVariablesForBytecodeInlinerLowering",
description = "Add fake locals to identify the range of inlined functions and lambdas" description = "Add fake locals to identify the range of inlined functions and lambdas"
) )
internal class FakeInliningLocalVariablesLowering(val context: JvmBackendContext) : IrInlineReferenceLocator(context), FileLoweringPass { interface FakeInliningLocalVariables<Container : IrElement> {
val context: JvmBackendContext
fun Container.addFakeLocalVariable(name: String)
fun Container.addFakeLocalVariableForFun(declaration: IrDeclaration) {
if (declaration !is IrFunction) return
if (declaration.isInline && !declaration.origin.isSynthetic && declaration.body != null && !declaration.isInlineOnly()) {
val currentFunctionName = context.defaultMethodSignatureMapper.mapFunctionName(declaration)
val localName = "${JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION}$currentFunctionName"
this.addFakeLocalVariable(localName)
}
}
fun Container.addFakeLocalVariableForLambda(argument: IrAttributeContainer, callee: IrFunction) {
val argumentToFunctionName = context.defaultMethodSignatureMapper.mapFunctionName(callee)
val lambdaReferenceName = context.getLocalClassType(argument)!!.internalName.substringAfterLast("/")
val localName = "${JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT}-$argumentToFunctionName-$lambdaReferenceName"
this.addFakeLocalVariable(localName)
}
}
internal class FakeLocalVariablesForBytecodeInlinerLowering(
override val context: JvmBackendContext
) : IrInlineReferenceLocator(context), FakeInliningLocalVariables<IrFunction>, FileLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.accept(this, null) irFile.accept(this, null)
} }
override fun visitFunction(declaration: IrFunction, data: IrDeclaration?) { override fun visitFunction(declaration: IrFunction, data: IrDeclaration?) {
super.visitFunction(declaration, data) super.visitFunction(declaration, data)
if (declaration.isInline && !declaration.origin.isSynthetic && declaration.body != null && !declaration.isInlineOnly()) { declaration.addFakeLocalVariableForFun(declaration)
val currentFunctionName = context.defaultMethodSignatureMapper.mapFunctionName(declaration)
val localName = "${JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION}$currentFunctionName"
declaration.addFakeLocalVariable(localName)
}
} }
override fun visitInlineLambda(argument: IrFunctionReference, callee: IrFunction, parameter: IrValueParameter, scope: IrDeclaration) { override fun visitInlineLambda(argument: IrFunctionReference, callee: IrFunction, parameter: IrValueParameter, scope: IrDeclaration) {
val lambda = argument.symbol.owner val lambda = argument.symbol.owner
val argumentToFunctionName = context.defaultMethodSignatureMapper.mapFunctionName(callee) lambda.addFakeLocalVariableForLambda(argument, callee)
val lambdaReferenceName = context.getLocalClassType(argument)!!.internalName.substringAfterLast("/")
val localName = "${JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT}-$argumentToFunctionName-$lambdaReferenceName"
lambda.addFakeLocalVariable(localName)
} }
private fun IrFunction.addFakeLocalVariable(name: String) { override fun IrFunction.addFakeLocalVariable(name: String) {
body = context.createIrBuilder(symbol).irBlockBody { body = context.createIrBuilder(symbol).irBlockBody {
// Create temporary variable, but make sure it's origin is `DEFINED` so that // Create temporary variable, but make sure it's origin is `DEFINED` so that
// it will materialize in the code. // it will materialize in the code.
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
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.ir.isInlineOnly
import org.jetbrains.kotlin.backend.jvm.irInlinerIsEnabled import org.jetbrains.kotlin.backend.jvm.irInlinerIsEnabled
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
@@ -33,25 +32,25 @@ import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
internal val fakeInliningLocalVariablesAfterInlineLowering = makeIrFilePhase<JvmBackendContext>( internal val fakeLocalVariablesForIrInlinerLowering = makeIrFilePhase<JvmBackendContext>(
{ context -> { context ->
if (!context.irInlinerIsEnabled()) return@makeIrFilePhase FileLoweringPass.Empty if (!context.irInlinerIsEnabled()) return@makeIrFilePhase FileLoweringPass.Empty
FakeInliningLocalVariablesAfterInlineLowering(context) FakeLocalVariablesForIrInlinerLowering(context)
}, },
name = "FakeInliningLocalVariablesAfterInlineLowering", name = "FakeLocalVariablesForIrInlinerLowering",
description = """Add fake locals to identify the range of inlined functions and lambdas. description = """Add fake locals to identify the range of inlined functions and lambdas.
|This lowering adds fake locals into already inlined blocks.""".trimMargin() |This lowering adds fake locals into already inlined blocks.""".trimMargin()
) )
// TODO extract common code with FakeInliningLocalVariablesLowering internal class FakeLocalVariablesForIrInlinerLowering(
internal class FakeInliningLocalVariablesAfterInlineLowering( override val context: JvmBackendContext
val context: JvmBackendContext ) : IrElementVisitorVoid, FakeInliningLocalVariables<IrInlinedFunctionBlock>, FileLoweringPass {
) : IrElementVisitor<Unit, IrDeclaration?>, FileLoweringPass {
private val inlinedStack = mutableListOf<IrInlinedFunctionBlock>() private val inlinedStack = mutableListOf<IrInlinedFunctionBlock>()
private var container: IrDeclaration? = null
private fun IrInlinedFunctionBlock.insertInStackAndProcess(data: IrDeclaration?) { private fun IrInlinedFunctionBlock.insertInStackAndProcess() {
inlinedStack += this inlinedStack += this
super.visitBlock(this, data) this.acceptChildren(this@FakeLocalVariablesForIrInlinerLowering, null)
inlinedStack.removeLast() inlinedStack.removeLast()
} }
@@ -61,47 +60,42 @@ internal class FakeInliningLocalVariablesAfterInlineLowering(
irFile.accept(LocalVariablesProcessor(), LocalVariablesProcessor.Data(processingOriginalDeclarations = false)) irFile.accept(LocalVariablesProcessor(), LocalVariablesProcessor.Data(processingOriginalDeclarations = false))
} }
override fun visitElement(element: IrElement, data: IrDeclaration?) { override fun visitElement(element: IrElement) {
val newData = if (element is IrDeclaration && element !is IrVariable) element else data val oldContainer = container
element.acceptChildren(this, newData) try {
container = if (element is IrDeclaration && element !is IrVariable) element else container
element.acceptChildren(this, null)
} finally {
container = oldContainer
}
} }
override fun visitBlock(expression: IrBlock, data: IrDeclaration?) { override fun visitBlock(expression: IrBlock) {
when { when {
expression is IrInlinedFunctionBlock && expression.isFunctionInlining() -> handleInlineFunction(expression, data) expression is IrInlinedFunctionBlock && expression.isFunctionInlining() -> handleInlineFunction(expression)
expression is IrInlinedFunctionBlock && expression.isLambdaInlining() -> handleInlineLambda(expression, data) expression is IrInlinedFunctionBlock && expression.isLambdaInlining() -> handleInlineLambda(expression)
else -> super.visitBlock(expression, data) else -> super.visitBlock(expression)
} }
} }
private fun handleInlineFunction(expression: IrInlinedFunctionBlock, data: IrDeclaration?) { private fun handleInlineFunction(expression: IrInlinedFunctionBlock) {
expression.insertInStackAndProcess(data) expression.insertInStackAndProcess()
val declaration = expression.inlineDeclaration val declaration = expression.inlineDeclaration
if (declaration is IrFunction && declaration.isInline && !declaration.origin.isSynthetic && declaration.body != null && !declaration.isInlineOnly()) { expression.addFakeLocalVariableForFun(declaration)
val currentFunctionName = context.defaultMethodSignatureMapper.mapFunctionName(declaration)
val localName = "${JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION}$currentFunctionName"
expression.addFakeLocalVariable(localName, data!!)
}
} }
private fun handleInlineLambda(expression: IrInlinedFunctionBlock, data: IrDeclaration?) { private fun handleInlineLambda(expression: IrInlinedFunctionBlock) {
expression.insertInStackAndProcess(data) expression.insertInStackAndProcess()
// `inlinedElement` here can be either `IrFunctionExpression` or `IrFunctionReference`, so cast must be safe // `inlinedElement` here can be either `IrFunctionExpression` or `IrFunctionReference`, so cast must be safe
val argument = expression.inlinedElement as IrAttributeContainer val argument = expression.inlinedElement as IrAttributeContainer
val callee = inlinedStack.extractDeclarationWhereGivenElementWasInlined(argument) as? IrFunction ?: return val callee = inlinedStack.extractDeclarationWhereGivenElementWasInlined(argument) as? IrFunction ?: return
expression.addFakeLocalVariableForLambda(argument, callee)
val argumentToFunctionName = context.defaultMethodSignatureMapper.mapFunctionName(callee)
val lambdaReferenceName = context.getLocalClassType(argument)!!.internalName.substringAfterLast("/")
val localName = "${JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT}-$argumentToFunctionName-$lambdaReferenceName"
expression.addFakeLocalVariable(localName, data!!)
} }
private fun IrInlinedFunctionBlock.addFakeLocalVariable(localName: String, container: IrDeclaration) { override fun IrInlinedFunctionBlock.addFakeLocalVariable(name: String) {
with(context.createIrBuilder(container.symbol)) { with(context.createIrBuilder(container!!.symbol)) {
val tmpVar = scope.createTmpVariable( val tmpVar = scope.createTmpVariable(
irInt(0), localName.removeSuffix(FOR_INLINE_SUFFIX), origin = IrDeclarationOrigin.DEFINED irInt(0), name.removeSuffix(FOR_INLINE_SUFFIX), origin = IrDeclarationOrigin.DEFINED
) )
this@addFakeLocalVariable.putStatementsInFrontOfInlinedFunction(listOf(tmpVar)) this@addFakeLocalVariable.putStatementsInFrontOfInlinedFunction(listOf(tmpVar))
} }