Add new "invent name" phase to generate names for regenerated classes
This commit is contained in:
+36
-5
@@ -6,19 +6,25 @@
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.getAdditionalStatementsFromInlinedBlock
|
||||
import org.jetbrains.kotlin.backend.common.ir.getNonDefaultAdditionalStatementsFromInlinedBlock
|
||||
import org.jetbrains.kotlin.backend.common.ir.getOriginalStatementsFromInlinedBlock
|
||||
import org.jetbrains.kotlin.backend.common.ir.isFunctionInlining
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.isAnonymousObject
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.NameUtils
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toUpperCaseAsciiOnly
|
||||
import kotlin.collections.set
|
||||
|
||||
abstract class InventNamesForLocalClasses(private val allowTopLevelCallables: Boolean) : FileLoweringPass {
|
||||
abstract class InventNamesForLocalClasses(
|
||||
private val allowTopLevelCallables: Boolean,
|
||||
private val generateNamesForRegeneratedObjects: Boolean = false
|
||||
) : FileLoweringPass {
|
||||
|
||||
protected abstract fun computeTopLevelClassName(clazz: IrClass): String
|
||||
protected abstract fun sanitizeNameIfNeeded(name: String): String
|
||||
@@ -33,7 +39,7 @@ abstract class InventNamesForLocalClasses(private val allowTopLevelCallables: Bo
|
||||
* @property enclosingName internal name of the enclosing class (including anonymous classes, local objects and callable references)
|
||||
* @property isLocal true if the next declaration to be encountered in the IR tree is local
|
||||
*/
|
||||
private data class Data(val enclosingName: String?, val isLocal: Boolean) {
|
||||
private data class Data(val enclosingName: String?, val isLocal: Boolean, val processingInlinedFunction: Boolean = false) {
|
||||
fun makeLocal(): Data = if (isLocal) this else copy(isLocal = true)
|
||||
}
|
||||
|
||||
@@ -41,6 +47,25 @@ abstract class InventNamesForLocalClasses(private val allowTopLevelCallables: Bo
|
||||
private val anonymousClassesCount = mutableMapOf<String, Int>()
|
||||
private val localFunctionNames = mutableMapOf<IrFunctionSymbol, String>()
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression, data: Data) {
|
||||
if (expression is IrInlinedFunctionBlock && !generateNamesForRegeneratedObjects) {
|
||||
return expression.getNonDefaultAdditionalStatementsFromInlinedBlock().forEach { it.accept(this, data) }
|
||||
}
|
||||
|
||||
if (!data.processingInlinedFunction && expression is IrInlinedFunctionBlock && expression.isFunctionInlining()) {
|
||||
expression.getAdditionalStatementsFromInlinedBlock().forEach { it.accept(this, data) }
|
||||
|
||||
val inlinedAt = expression.inlineCall.symbol.owner.name.asString()
|
||||
val newData = data.copy(
|
||||
enclosingName = data.enclosingName + "$\$inlined\$$inlinedAt", isLocal = true, processingInlinedFunction = true
|
||||
)
|
||||
expression.getOriginalStatementsFromInlinedBlock().forEach { it.accept(this, newData) }
|
||||
|
||||
return
|
||||
}
|
||||
super.visitContainerExpression(expression, data)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass, data: Data) {
|
||||
if (!data.isLocal) {
|
||||
// This is not a local class, so we need not invent a name for it, the type mapper will correctly compute it
|
||||
@@ -99,6 +124,8 @@ abstract class InventNamesForLocalClasses(private val allowTopLevelCallables: Bo
|
||||
localFunctionNames[declaration.symbol] = name
|
||||
}
|
||||
}
|
||||
|
||||
declaration is IrVariable && generateNamesForRegeneratedObjects || data.processingInlinedFunction -> enclosingName
|
||||
enclosingName != null -> "$enclosingName$$simpleName"
|
||||
else -> simpleName
|
||||
}
|
||||
@@ -115,6 +142,10 @@ abstract class InventNamesForLocalClasses(private val allowTopLevelCallables: Bo
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, data: Data) {
|
||||
if (data.processingInlinedFunction && expression.attributeOwnerIdBeforeInline == null) {
|
||||
// skip IrFunctionReference from `singleArgumentInlineFunction`
|
||||
return
|
||||
}
|
||||
val internalName = localFunctionNames[expression.symbol] ?: inventName(null, data)
|
||||
putLocalClassName(expression, internalName)
|
||||
|
||||
|
||||
@@ -342,6 +342,7 @@ private val jvmFilePhases = listOf(
|
||||
// makePatchParentsPhase(),
|
||||
|
||||
removeDuplicatedInlinedLocalClasses,
|
||||
inventNamesForInlinedLocalClassesPhase,
|
||||
|
||||
jvmLocalClassExtractionPhase,
|
||||
staticCallableReferencePhase,
|
||||
|
||||
+28
-14
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.coroutines.*
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
|
||||
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.*
|
||||
@@ -36,9 +37,7 @@ import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.extractTypeParameters
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
@@ -291,9 +290,8 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
||||
}
|
||||
|
||||
private fun addContinuationObjectAndContinuationParameterToSuspendFunctions(irFile: IrFile) {
|
||||
class MutableFlag(var capturesCrossinline: Boolean)
|
||||
irFile.accept(object : IrElementTransformer<MutableFlag?> {
|
||||
override fun visitClass(declaration: IrClass, data: MutableFlag?): IrStatement {
|
||||
irFile.accept(object : IrElementTransformerVoid() {
|
||||
override fun visitClass(declaration: IrClass): IrStatement {
|
||||
declaration.transformDeclarationsFlat {
|
||||
if (it is IrSimpleFunction && it.isSuspend)
|
||||
return@transformDeclarationsFlat transformToView(it)
|
||||
@@ -304,9 +302,9 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
||||
}
|
||||
|
||||
private fun transformToView(function: IrSimpleFunction): List<IrFunction> {
|
||||
val flag = MutableFlag(false)
|
||||
function.accept(this, flag)
|
||||
function.accept(this, null)
|
||||
|
||||
val capturesCrossinline = function.isCapturingCrossinline()
|
||||
val view = function.suspendFunctionViewOrStub(context)
|
||||
val continuationParameter = view.continuationParameter()
|
||||
val parameterMap = function.explicitParameters.zip(view.explicitParameters.filter { it != continuationParameter }).toMap()
|
||||
@@ -327,7 +325,7 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
||||
)
|
||||
}
|
||||
|
||||
if (flag.capturesCrossinline || function.isInline) {
|
||||
if (capturesCrossinline || function.isInline) {
|
||||
result += context.irFactory.buildFun {
|
||||
containerSource = view.containerSource
|
||||
name = Name.identifier(context.defaultMethodSignatureMapper.mapFunctionName(view) + FOR_INLINE_SUFFIX)
|
||||
@@ -359,7 +357,7 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
||||
newFunction,
|
||||
view.dispatchReceiverParameter,
|
||||
function as IrAttributeContainer,
|
||||
flag.capturesCrossinline
|
||||
capturesCrossinline
|
||||
)
|
||||
if (newFunction.body is IrExpressionBody) {
|
||||
+irReturn(newFunction.body!!.statements[0] as IrExpression)
|
||||
@@ -372,10 +370,26 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
||||
return result
|
||||
}
|
||||
|
||||
override fun visitFieldAccess(expression: IrFieldAccessExpression, data: MutableFlag?): IrExpression {
|
||||
if (expression.symbol.owner.origin == LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE)
|
||||
data?.capturesCrossinline = true
|
||||
return super.visitFieldAccess(expression, data)
|
||||
private fun IrSimpleFunction.isCapturingCrossinline(): Boolean {
|
||||
var capturesCrossinline = false
|
||||
(this.attributeOwnerIdBeforeInline ?: this).acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFieldAccess(expression: IrFieldAccessExpression) {
|
||||
if (expression.symbol.owner.origin == LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE) {
|
||||
capturesCrossinline = true
|
||||
return
|
||||
}
|
||||
super.visitFieldAccess(expression)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
return
|
||||
}
|
||||
})
|
||||
return capturesCrossinline
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
+20
-1
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.InventNamesForLocalClasses
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
||||
@@ -25,7 +26,17 @@ val inventNamesForLocalClassesPhase = makeIrModulePhase(
|
||||
prerequisite = setOf(mainMethodGenerationPhase)
|
||||
)
|
||||
|
||||
class JvmInventNamesForLocalClasses(private val context: JvmBackendContext) : InventNamesForLocalClasses(allowTopLevelCallables = false) {
|
||||
val inventNamesForInlinedLocalClassesPhase = makeIrFilePhase(
|
||||
{ context -> JvmInventNamesForInlinedAnonymousObjects(context) },
|
||||
name = "InventNamesForInlinedLocalClasses",
|
||||
description = "Invent names for INLINED local classes and anonymous objects",
|
||||
prerequisite = setOf(inventNamesForLocalClassesPhase, removeDuplicatedInlinedLocalClasses)
|
||||
)
|
||||
|
||||
open class JvmInventNamesForLocalClasses(
|
||||
protected val context: JvmBackendContext,
|
||||
generateNamesForRegeneratedObjects: Boolean = false
|
||||
) : InventNamesForLocalClasses(allowTopLevelCallables = true, generateNamesForRegeneratedObjects) {
|
||||
override fun computeTopLevelClassName(clazz: IrClass): String {
|
||||
val file = clazz.parent as? IrFile
|
||||
?: throw AssertionError("Top-level class expected: ${clazz.render()}")
|
||||
@@ -48,3 +59,11 @@ class JvmInventNamesForLocalClasses(private val context: JvmBackendContext) : In
|
||||
context.putLocalClassType(declaration, Type.getObjectType(localClassName))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO try to use only one "InventNames"
|
||||
class JvmInventNamesForInlinedAnonymousObjects(context: JvmBackendContext) : JvmInventNamesForLocalClasses(context, true) {
|
||||
override fun putLocalClassName(declaration: IrAttributeContainer, localClassName: String) {
|
||||
if (declaration.attributeOwnerIdBeforeInline == null) return
|
||||
context.putLocalClassType(declaration, Type.getObjectType(localClassName))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user