JVM_IR: generate more correct names for regenerated objects

and fake lambda types, too. (But those only matter for debugging.)

Also, share object name generators between methods with the same name to
avoid rewriting objects from one with objects from the other.
This commit is contained in:
pyos
2019-08-30 09:45:34 +02:00
committed by max-kammerer
parent 58775275e7
commit 07bde889b4
12 changed files with 74 additions and 16 deletions
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.MemoizedInlineClassReplacements import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.MemoizedInlineClassReplacements
import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.inline.NameGenerator
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.psi2ir.PsiSourceManager
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
@@ -71,6 +73,13 @@ class JvmBackendContext(
localClassInfo[container.attributeOwnerId] = value localClassInfo[container.attributeOwnerId] = value
} }
// TODO cache these at ClassCodegen level. Currently, sharing this map between classes in a module is required
// because IrSourceCompilerForInline constructs a new (Fake)ClassCodegen for every call to
// an inline function in the same module. Thus, if two inline functions happen to have the same name
// and call a third inline function that has an anonymous object, the one which is called last
// will overwrite the other's regenerated copy. (Or don't recompile the inline function for every call.)
internal val regeneratedObjectNameGenerators = mutableMapOf<Pair<IrClass, Name>, NameGenerator>()
internal val localDelegatedProperties = mutableMapOf<IrClass, List<IrLocalDelegatedPropertySymbol>>() internal val localDelegatedProperties = mutableMapOf<IrClass, List<IrLocalDelegatedPropertySymbol>>()
internal val multifileFacadesToAdd = mutableMapOf<JvmClassName, MutableList<IrClass>>() internal val multifileFacadesToAdd = mutableMapOf<JvmClassName, MutableList<IrClass>>()
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.lower.constantValue
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper
import org.jetbrains.kotlin.codegen.inline.NameGenerator
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages
import org.jetbrains.kotlin.codegen.inline.SourceMapper import org.jetbrains.kotlin.codegen.inline.SourceMapper
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
@@ -82,6 +84,13 @@ open class ClassCodegen protected constructor(
else -> null else -> null
} }
fun getRegeneratedObjectNameGenerator(function: IrFunction): NameGenerator {
val name = if (function.name.isSpecial) Name.identifier("special") else function.name
return context.regeneratedObjectNameGenerators.getOrPut(irClass to name) {
NameGenerator("${type.internalName}\$$name\$\$inlined")
}
}
fun generate(): ReifiedTypeParametersUsages { fun generate(): ReifiedTypeParametersUsages {
if (withinInline) { if (withinInline) {
getOrCreateSourceMapper() //initialize default mapping that would be later written in class file getOrCreateSourceMapper() //initialize default mapping that would be later written in class file
@@ -116,7 +116,7 @@ class ExpressionCodegen(
override val visitor: InstructionAdapter override val visitor: InstructionAdapter
get() = mv get() = mv
override val inlineNameGenerator: NameGenerator = NameGenerator("${classCodegen.type.internalName}\$todo") // TODO override val inlineNameGenerator: NameGenerator = classCodegen.getRegeneratedObjectNameGenerator(irFunction)
override val typeSystem: TypeSystemCommonBackendContext override val typeSystem: TypeSystemCommonBackendContext
get() = typeMapper.typeSystem get() = typeMapper.typeSystem
@@ -151,11 +151,14 @@ class IrExpressionLambdaImpl(
return false //always false return false //always false
} }
companion object { // This name doesn't actually matter: it is used internally to tell this lambda's captured
private var counter: Int = 123//TODO: pass proper type // arguments apart from any other scope's. So long as it's unique, any value is fine.
} // This particular string slightly aids in debugging internal compiler errors as it at least
// points towards the function containing the lambda.
override val lambdaClassType: Type = Type.getObjectType("test${counter++}") override val lambdaClassType: Type = Type.getObjectType(
context.getLocalClassInfo(reference)?.internalName
?: throw AssertionError("callable reference ${reference.dump()} has no name in context")
)
override val capturedVars: List<CapturedParamDesc> = override val capturedVars: List<CapturedParamDesc> =
arrayListOf<CapturedParamDesc>().apply { arrayListOf<CapturedParamDesc>().apply {
@@ -24,10 +24,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
@@ -51,6 +48,7 @@ internal val inlineCallableReferenceToLambdaPhase = makeIrFilePhase(
// //
internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendContext) : FileLoweringPass { internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendContext) : FileLoweringPass {
private val inlinableCR = mutableSetOf<IrCallableReference>() private val inlinableCR = mutableSetOf<IrCallableReference>()
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
@@ -118,7 +116,9 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte
expression.startOffset, expression.endOffset, field.type, expression.startOffset, expression.endOffset, field.type,
newLambda.symbol, newLambda.symbol.descriptor, 0, newLambda.symbol, newLambda.symbol.descriptor, 0,
IrStatementOrigin.LAMBDA IrStatementOrigin.LAMBDA
) ).apply {
copyAttributes(expression)
}
} }
} }
@@ -209,7 +209,9 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte
expression.startOffset, expression.endOffset, referencedFunction.returnType, expression.startOffset, expression.endOffset, referencedFunction.returnType,
newLambda.symbol, newLambda.symbol.descriptor, referencedFunction.typeParameters.size, newLambda.symbol, newLambda.symbol.descriptor, referencedFunction.typeParameters.size,
IrStatementOrigin.LAMBDA IrStatementOrigin.LAMBDA
) ).apply {
copyAttributes(expression)
}
} }
} }
} }
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
package test package test
@@ -0,0 +1,19 @@
// FILE: 1.kt
package test
inline fun <R> call(crossinline f: () -> R) : R {
return { f() }()
}
// FILE: 2.kt
//NO_CHECK_LAMBDA_INLINING
import test.*
inline fun sameName(s: Long): String = call { "FAIL" }
inline fun sameName(s: Int): String = call { "OK" }
fun box(): String {
val result = sameName(1)
sameName(1L)
return result
}
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
package test package test
@@ -1888,6 +1888,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt"); runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt");
} }
@TestMetadata("regeneratedLambdaName2.kt")
public void testRegeneratedLambdaName2() throws Exception {
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt");
}
@TestMetadata("sameCaptured.kt") @TestMetadata("sameCaptured.kt")
public void testSameCaptured() throws Exception { public void testSameCaptured() throws Exception {
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt"); runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt");
@@ -1888,6 +1888,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt"); runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt");
} }
@TestMetadata("regeneratedLambdaName2.kt")
public void testRegeneratedLambdaName2() throws Exception {
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt");
}
@TestMetadata("sameCaptured.kt") @TestMetadata("sameCaptured.kt")
public void testSameCaptured() throws Exception { public void testSameCaptured() throws Exception {
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt"); runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt");
@@ -1888,6 +1888,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt"); runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt");
} }
@TestMetadata("regeneratedLambdaName2.kt")
public void testRegeneratedLambdaName2() throws Exception {
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt");
}
@TestMetadata("sameCaptured.kt") @TestMetadata("sameCaptured.kt")
public void testSameCaptured() throws Exception { public void testSameCaptured() throws Exception {
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt"); runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt");
@@ -1888,6 +1888,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt"); runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt");
} }
@TestMetadata("regeneratedLambdaName2.kt")
public void testRegeneratedLambdaName2() throws Exception {
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt");
}
@TestMetadata("sameCaptured.kt") @TestMetadata("sameCaptured.kt")
public void testSameCaptured() throws Exception { public void testSameCaptured() throws Exception {
runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt"); runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt");