[JVM_IR] Unify code between fake variables lowerings
#KT-58778 Fixed
This commit is contained in:
@@ -455,8 +455,8 @@ private val jvmFilePhases = listOf(
|
|||||||
replaceNumberToCharCallSitesPhase,
|
replaceNumberToCharCallSitesPhase,
|
||||||
|
|
||||||
renameFieldsPhase,
|
renameFieldsPhase,
|
||||||
fakeInliningLocalVariablesLowering,
|
fakeLocalVariablesForBytecodeInlinerLowering,
|
||||||
fakeInliningLocalVariablesAfterInlineLowering,
|
fakeLocalVariablesForIrInlinerLowering,
|
||||||
|
|
||||||
// makePatchParentsPhase()
|
// makePatchParentsPhase()
|
||||||
)
|
)
|
||||||
|
|||||||
+32
-14
@@ -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.
|
||||||
+30
-36
@@ -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))
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user