JVM IR: link via descriptors instead of signatures by default
Doing so speeds up psi2ir ~2 times, and thus improves total compiler performance by about 6-8%. Unless JVM IR is in the mode where linking via signatures is the only way (-Xserialize-ir, -Xklib), signatures are actually not needed at all, SymbolTable can use the frontend representation (descriptors for FE1.0, and hopefully FIR elements for K2) as hash table keys. The only catch is that since other backends still need to work with signatures, all the common IR utilities, such as irTypePredicates.kt, need to work correctly for IR elements both with signatures and without. Also, introduce a fallback compiler flag -Xlink-via-signatures, in case something goes wrong, to be able to troubleshoot and workaround any issues. #KT-48233
This commit is contained in:
+9
-2
@@ -478,8 +478,8 @@ Also sets `-jvm-target` value equal to the selected JDK version"""
|
|||||||
|
|
||||||
@Argument(
|
@Argument(
|
||||||
value = "-Xtype-enhancement-improvements-strict-mode",
|
value = "-Xtype-enhancement-improvements-strict-mode",
|
||||||
description = "Enable strict mode for some improvements in the type enhancement for loaded Java types based on nullability annotations," +
|
description = "Enable strict mode for some improvements in the type enhancement for loaded Java types based on nullability annotations,\n" +
|
||||||
"including freshly supported reading of the type use annotations from class files. " +
|
"including freshly supported reading of the type use annotations from class files.\n" +
|
||||||
"See KT-45671 for more details"
|
"See KT-45671 for more details"
|
||||||
)
|
)
|
||||||
var typeEnhancementImprovementsInStrictMode: Boolean by FreezableVar(false)
|
var typeEnhancementImprovementsInStrictMode: Boolean by FreezableVar(false)
|
||||||
@@ -509,6 +509,13 @@ Also sets `-jvm-target` value equal to the selected JDK version"""
|
|||||||
)
|
)
|
||||||
var enhanceTypeParameterTypesToDefNotNull: Boolean by FreezableVar(false)
|
var enhanceTypeParameterTypesToDefNotNull: Boolean by FreezableVar(false)
|
||||||
|
|
||||||
|
@Argument(
|
||||||
|
value = "-Xlink-via-signatures",
|
||||||
|
description = "Link JVM IR symbols via signatures, instead of descriptors. \n" +
|
||||||
|
"This mode is slower, but can be useful in troubleshooting problems with the JVM IR backend"
|
||||||
|
)
|
||||||
|
var linkViaSignatures: Boolean by FreezableVar(false)
|
||||||
|
|
||||||
override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> {
|
override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> {
|
||||||
val result = super.configureAnalysisFlags(collector, languageVersion)
|
val result = super.configureAnalysisFlags(collector, languageVersion)
|
||||||
result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics
|
result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics
|
||||||
|
|||||||
@@ -288,6 +288,8 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
|
|||||||
put(JVMConfigurationKeys.VALIDATE_IR, arguments.validateIr)
|
put(JVMConfigurationKeys.VALIDATE_IR, arguments.validateIr)
|
||||||
put(JVMConfigurationKeys.VALIDATE_BYTECODE, arguments.validateBytecode)
|
put(JVMConfigurationKeys.VALIDATE_BYTECODE, arguments.validateBytecode)
|
||||||
|
|
||||||
|
put(JVMConfigurationKeys.LINK_VIA_SIGNATURES, arguments.linkViaSignatures)
|
||||||
|
|
||||||
val assertionsMode =
|
val assertionsMode =
|
||||||
JVMAssertionsMode.fromStringOrNull(arguments.assertionsMode)
|
JVMAssertionsMode.fromStringOrNull(arguments.assertionsMode)
|
||||||
if (assertionsMode == null) {
|
if (assertionsMode == null) {
|
||||||
|
|||||||
@@ -153,4 +153,7 @@ public class JVMConfigurationKeys {
|
|||||||
|
|
||||||
public static final CompilerConfigurationKey<Boolean> VALIDATE_BYTECODE =
|
public static final CompilerConfigurationKey<Boolean> VALIDATE_BYTECODE =
|
||||||
CompilerConfigurationKey.create("Validate generated JVM bytecode");
|
CompilerConfigurationKey.create("Validate generated JVM bytecode");
|
||||||
|
|
||||||
|
public static final CompilerConfigurationKey<Boolean> LINK_VIA_SIGNATURES =
|
||||||
|
CompilerConfigurationKey.create("Link JVM IR symbols via signatures, instead of by descriptors");
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -18,10 +18,11 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.path
|
import org.jetbrains.kotlin.ir.declarations.path
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
|
||||||
import org.jetbrains.kotlin.ir.util.file
|
import org.jetbrains.kotlin.ir.util.file
|
||||||
|
import org.jetbrains.kotlin.ir.util.hasEqualFqName
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class KtDiagnosticReporterWithImplicitIrBasedContext(
|
class KtDiagnosticReporterWithImplicitIrBasedContext(
|
||||||
@@ -118,7 +119,7 @@ internal class IrBasedSuppressCache : AbstractKotlinSuppressCache<IrElement>() {
|
|||||||
|
|
||||||
private fun collectSuppressAnnotationKeys(element: IrElement): Boolean =
|
private fun collectSuppressAnnotationKeys(element: IrElement): Boolean =
|
||||||
(element as? IrAnnotationContainer)?.annotations?.filter {
|
(element as? IrAnnotationContainer)?.annotations?.filter {
|
||||||
it.type.classifierOrNull?.signature == SUPPRESS
|
it.type.classOrNull?.owner?.hasEqualFqName(SUPPRESS) == true
|
||||||
}?.flatMap {
|
}?.flatMap {
|
||||||
buildList {
|
buildList {
|
||||||
fun addIfStringConst(irConst: IrConst<*>) {
|
fun addIfStringConst(irConst: IrConst<*>) {
|
||||||
@@ -153,4 +154,4 @@ internal class IrBasedSuppressCache : AbstractKotlinSuppressCache<IrElement>() {
|
|||||||
override fun getSuppressingStrings(annotated: IrElement): Set<String> = annotationKeys[annotated].orEmpty()
|
override fun getSuppressingStrings(annotated: IrElement): Set<String> = annotationKeys[annotated].orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val SUPPRESS = IdSignature.CommonSignature("kotlin", "Suppress", null, 0)
|
private val SUPPRESS = FqName("kotlin.Suppress")
|
||||||
|
|||||||
+3
-2
@@ -16,13 +16,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common
|
package org.jetbrains.kotlin.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.types.IdSignatureValues
|
import org.jetbrains.kotlin.ir.types.isClassWithFqName
|
||||||
import org.jetbrains.kotlin.ir.types.isUnit
|
import org.jetbrains.kotlin.ir.types.isUnit
|
||||||
import org.jetbrains.kotlin.ir.util.usesDefaultArguments
|
import org.jetbrains.kotlin.ir.util.usesDefaultArguments
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
@@ -98,7 +99,7 @@ fun collectTailRecursionCalls(irFunction: IrFunction, followFunctionReference: (
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun IrExpression.isUnitRead(): Boolean =
|
private fun IrExpression.isUnitRead(): Boolean =
|
||||||
this is IrGetObjectValue && symbol.signature == IdSignatureValues.unit
|
this is IrGetObjectValue && symbol.isClassWithFqName(StandardNames.FqNames.unit)
|
||||||
|
|
||||||
override fun visitWhen(expression: IrWhen, data: ElementKind) {
|
override fun visitWhen(expression: IrWhen, data: ElementKind) {
|
||||||
expression.branches.forEach {
|
expression.branches.forEach {
|
||||||
|
|||||||
+11
-2
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.phaser.*
|
|||||||
import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl
|
import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl
|
||||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.getKtFile
|
import org.jetbrains.kotlin.backend.jvm.ir.getKtFile
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.serialization.DisabledIdSignatureDescriptor
|
||||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
||||||
import org.jetbrains.kotlin.codegen.CodegenFactory
|
import org.jetbrains.kotlin.codegen.CodegenFactory
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
@@ -73,11 +74,18 @@ open class JvmIrCodegenFactory(
|
|||||||
) : CodegenFactory.CodegenInput
|
) : CodegenFactory.CodegenInput
|
||||||
|
|
||||||
override fun convertToIr(input: CodegenFactory.IrConversionInput): JvmIrBackendInput {
|
override fun convertToIr(input: CodegenFactory.IrConversionInput): JvmIrBackendInput {
|
||||||
|
val enableIdSignatures =
|
||||||
|
input.configuration.getBoolean(JVMConfigurationKeys.LINK_VIA_SIGNATURES) ||
|
||||||
|
input.configuration[JVMConfigurationKeys.SERIALIZE_IR, JvmSerializeIrMode.NONE] != JvmSerializeIrMode.NONE ||
|
||||||
|
input.configuration[JVMConfigurationKeys.KLIB_PATHS, emptyList()].isNotEmpty()
|
||||||
val (mangler, symbolTable) =
|
val (mangler, symbolTable) =
|
||||||
if (externalSymbolTable != null) externalMangler!! to externalSymbolTable
|
if (externalSymbolTable != null) externalMangler!! to externalSymbolTable
|
||||||
else {
|
else {
|
||||||
val mangler = JvmDescriptorMangler(MainFunctionDetector(input.bindingContext, input.languageVersionSettings))
|
val mangler = JvmDescriptorMangler(MainFunctionDetector(input.bindingContext, input.languageVersionSettings))
|
||||||
val symbolTable = SymbolTable(JvmIdSignatureDescriptor(mangler), IrFactoryImpl)
|
val signaturer =
|
||||||
|
if (enableIdSignatures) JvmIdSignatureDescriptor(mangler)
|
||||||
|
else DisabledIdSignatureDescriptor
|
||||||
|
val symbolTable = SymbolTable(signaturer, IrFactoryImpl)
|
||||||
mangler to symbolTable
|
mangler to symbolTable
|
||||||
}
|
}
|
||||||
val psi2ir = Psi2IrTranslator(input.languageVersionSettings, Psi2IrConfiguration(input.ignoreErrors))
|
val psi2ir = Psi2IrTranslator(input.languageVersionSettings, Psi2IrConfiguration(input.ignoreErrors))
|
||||||
@@ -114,7 +122,8 @@ open class JvmIrCodegenFactory(
|
|||||||
symbolTable,
|
symbolTable,
|
||||||
frontEndContext,
|
frontEndContext,
|
||||||
stubGenerator,
|
stubGenerator,
|
||||||
mangler
|
mangler,
|
||||||
|
enableIdSignatures,
|
||||||
)
|
)
|
||||||
|
|
||||||
val pluginContext by lazy {
|
val pluginContext by lazy {
|
||||||
|
|||||||
+3
-6
@@ -121,7 +121,9 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
annotations =
|
annotations =
|
||||||
if (isMultifilePart) irFile.annotations.filterNot { it.symbol.owner.parentAsClass.symbol.signature == JVM_NAME }
|
if (isMultifilePart) irFile.annotations.filterNot {
|
||||||
|
it.symbol.owner.parentAsClass.hasEqualFqName(JvmFileClassUtil.JVM_NAME)
|
||||||
|
}
|
||||||
else irFile.annotations
|
else irFile.annotations
|
||||||
|
|
||||||
metadata = irFile.metadata
|
metadata = irFile.metadata
|
||||||
@@ -142,13 +144,8 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
|
||||||
private val JVM_NAME = IdSignature.CommonSignature("kotlin.jvm", "JvmName", null, 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun IrFile.getFileClassInfo(): JvmFileClassInfo =
|
fun IrFile.getFileClassInfo(): JvmFileClassInfo =
|
||||||
when (val fileEntry = this.fileEntry) {
|
when (val fileEntry = this.fileEntry) {
|
||||||
is PsiIrFileEntry ->
|
is PsiIrFileEntry ->
|
||||||
|
|||||||
+12
-12
@@ -24,12 +24,7 @@ import org.jetbrains.kotlin.ir.builders.irSetField
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.copyWithOffsets
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
@@ -43,11 +38,16 @@ internal val jvmOptimizationLoweringPhase = makeIrFilePhase(
|
|||||||
)
|
)
|
||||||
|
|
||||||
class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass {
|
class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass {
|
||||||
|
private companion object {
|
||||||
companion object {
|
private fun isNegation(expression: IrExpression): Boolean =
|
||||||
fun isNegation(expression: IrExpression, context: JvmBackendContext): Boolean =
|
expression is IrCall && expression.symbol.owner.let { not ->
|
||||||
expression is IrCall &&
|
not.name == OperatorNameConventions.NOT &&
|
||||||
(expression.symbol as? IrPublicSymbolBase<*>)?.signature == context.irBuiltIns.booleanNotSymbol.signature
|
not.extensionReceiverParameter == null &&
|
||||||
|
not.valueParameters.isEmpty() &&
|
||||||
|
not.dispatchReceiverParameter.let { receiver ->
|
||||||
|
receiver != null && receiver.type.isBoolean()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IrFunction.isObjectEquals
|
private val IrFunction.isObjectEquals
|
||||||
@@ -98,7 +98,7 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass
|
|||||||
return optimizePropertyAccess(expression, data)
|
return optimizePropertyAccess(expression, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNegation(expression, context) && isNegation(expression.dispatchReceiver!!, context)) {
|
if (isNegation(expression) && isNegation(expression.dispatchReceiver!!)) {
|
||||||
return (expression.dispatchReceiver as IrCall).dispatchReceiver!!
|
return (expression.dispatchReceiver as IrCall).dispatchReceiver!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
|||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
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.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.name.Name
|
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
|
||||||
@@ -144,9 +145,10 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin
|
|||||||
copyAttributes(reference)
|
copyAttributes(reference)
|
||||||
|
|
||||||
val function = reference.symbol.owner
|
val function = reference.symbol.owner
|
||||||
val isRestricted = reference.symbol.owner.extensionReceiverParameter?.type?.classOrNull?.owner?.annotations?.any {
|
val extensionReceiver = function.extensionReceiverParameter?.type?.classOrNull
|
||||||
it.type.classOrNull?.signature == IdSignature.CommonSignature("kotlin.coroutines", "RestrictsSuspension", null, 0)
|
val isRestricted = extensionReceiver != null && extensionReceiver.owner.annotations.any {
|
||||||
} == true
|
it.type.classOrNull?.isClassWithFqName(FqNameUnsafe("kotlin.coroutines.RestrictsSuspension")) == true
|
||||||
|
}
|
||||||
val suspendLambda =
|
val suspendLambda =
|
||||||
if (isRestricted) context.ir.symbols.restrictedSuspendLambdaClass.owner
|
if (isRestricted) context.ir.symbols.restrictedSuspendLambdaClass.owner
|
||||||
else context.ir.symbols.suspendLambdaClass.owner
|
else context.ir.symbols.suspendLambdaClass.owner
|
||||||
|
|||||||
@@ -481,22 +481,26 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
|
|||||||
).substitute(type as IrType)
|
).substitute(type as IrType)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun TypeConstructorMarker.getPrimitiveType(): PrimitiveType? {
|
override fun TypeConstructorMarker.getPrimitiveType(): PrimitiveType? =
|
||||||
|
getNameForClassUnderKotlinPackage()?.let(PrimitiveType::getByShortName)
|
||||||
|
|
||||||
|
override fun TypeConstructorMarker.getPrimitiveArrayType(): PrimitiveType? =
|
||||||
|
getNameForClassUnderKotlinPackage()?.let(PrimitiveType::getByShortArrayName)
|
||||||
|
|
||||||
|
private fun TypeConstructorMarker.getNameForClassUnderKotlinPackage(): String? {
|
||||||
if (this !is IrClassSymbol) return null
|
if (this !is IrClassSymbol) return null
|
||||||
|
|
||||||
val signature = signature?.asPublic()
|
val signature = signature?.asPublic()
|
||||||
if (signature == null || signature.packageFqName != "kotlin") return null
|
return if (signature != null) {
|
||||||
|
if (signature.packageFqName == StandardNames.BUILT_INS_PACKAGE_NAME.asString())
|
||||||
return PrimitiveType.getByShortName(signature.declarationFqName)
|
signature.declarationFqName
|
||||||
}
|
else null
|
||||||
|
} else {
|
||||||
override fun TypeConstructorMarker.getPrimitiveArrayType(): PrimitiveType? {
|
val parent = owner.parent
|
||||||
if (this !is IrClassSymbol) return null
|
if (parent is IrPackageFragment && parent.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME)
|
||||||
|
owner.name.asString()
|
||||||
val signature = signature?.asPublic()
|
else null
|
||||||
if (signature == null || signature.packageFqName != "kotlin") return null
|
}
|
||||||
|
|
||||||
return PrimitiveType.getByShortArrayName(signature.declarationFqName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun TypeConstructorMarker.isUnderKotlinPackage(): Boolean {
|
override fun TypeConstructorMarker.isUnderKotlinPackage(): Boolean {
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ import org.jetbrains.kotlin.builtins.PrimitiveType
|
|||||||
import org.jetbrains.kotlin.builtins.StandardNames
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||||
import org.jetbrains.kotlin.ir.util.hasEqualFqName
|
import org.jetbrains.kotlin.ir.util.hasEqualFqName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
@Suppress("ObjectPropertyName")
|
@Suppress("ObjectPropertyName")
|
||||||
object IdSignatureValues {
|
object IdSignatureValues {
|
||||||
@@ -55,9 +57,14 @@ fun getPublicSignature(packageFqName: FqName, name: String) =
|
|||||||
private fun IrType.isClassType(signature: IdSignature.CommonSignature, hasQuestionMark: Boolean? = null): Boolean {
|
private fun IrType.isClassType(signature: IdSignature.CommonSignature, hasQuestionMark: Boolean? = null): Boolean {
|
||||||
if (this !is IrSimpleType) return false
|
if (this !is IrSimpleType) return false
|
||||||
if (hasQuestionMark != null && this.hasQuestionMark != hasQuestionMark) return false
|
if (hasQuestionMark != null && this.hasQuestionMark != hasQuestionMark) return false
|
||||||
return signature == classifier.signature
|
return signature == classifier.signature ||
|
||||||
|
classifier.owner.let { it is IrClass && it.hasFqNameEqualToSignature(signature) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrClass.hasFqNameEqualToSignature(signature: IdSignature.CommonSignature): Boolean =
|
||||||
|
name.asString() == signature.shortName &&
|
||||||
|
hasEqualFqName(FqName("${signature.packageFqName}.${signature.declarationFqName}"))
|
||||||
|
|
||||||
fun IrClassifierSymbol.isClassWithFqName(fqName: FqNameUnsafe): Boolean =
|
fun IrClassifierSymbol.isClassWithFqName(fqName: FqNameUnsafe): Boolean =
|
||||||
this is IrClassSymbol && classFqNameEquals(this, fqName)
|
this is IrClassSymbol && classFqNameEquals(this, fqName)
|
||||||
|
|
||||||
@@ -71,6 +78,17 @@ private val idSignatureToPrimitiveType: Map<IdSignature.CommonSignature, Primiti
|
|||||||
getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, it.typeName.asString())
|
getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, it.typeName.asString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val shortNameToPrimitiveType: Map<Name, PrimitiveType> =
|
||||||
|
PrimitiveType.values().associateBy(PrimitiveType::typeName)
|
||||||
|
|
||||||
|
private val idSignatureToUnsignedType: Map<IdSignature.CommonSignature, UnsignedType> =
|
||||||
|
UnsignedType.values().associateBy {
|
||||||
|
getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, it.typeName.asString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private val shortNameToUnsignedType: Map<Name, UnsignedType> =
|
||||||
|
UnsignedType.values().associateBy(UnsignedType::typeName)
|
||||||
|
|
||||||
val primitiveArrayTypesSignatures: Map<PrimitiveType, IdSignature.CommonSignature> =
|
val primitiveArrayTypesSignatures: Map<PrimitiveType, IdSignature.CommonSignature> =
|
||||||
PrimitiveType.values().associateWith {
|
PrimitiveType.values().associateWith {
|
||||||
getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "${it.typeName.asString()}Array")
|
getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "${it.typeName.asString()}Array")
|
||||||
@@ -97,23 +115,24 @@ fun IrType.isPrimitiveType(hasQuestionMark: Boolean = false): Boolean =
|
|||||||
fun IrType.isNullablePrimitiveType(): Boolean = isPrimitiveType(true)
|
fun IrType.isNullablePrimitiveType(): Boolean = isPrimitiveType(true)
|
||||||
|
|
||||||
fun IrType.getPrimitiveType(): PrimitiveType? =
|
fun IrType.getPrimitiveType(): PrimitiveType? =
|
||||||
if (this is IrSimpleType && classifier is IrClassSymbol)
|
getPrimitiveOrUnsignedType(idSignatureToPrimitiveType, shortNameToPrimitiveType)
|
||||||
idSignatureToPrimitiveType[classifier.signature]
|
|
||||||
else null
|
|
||||||
|
|
||||||
fun IrType.isUnsignedType(hasQuestionMark: Boolean = false): Boolean =
|
fun IrType.isUnsignedType(hasQuestionMark: Boolean = false): Boolean =
|
||||||
this is IrSimpleType && hasQuestionMark == this.hasQuestionMark && getUnsignedType() != null
|
this is IrSimpleType && hasQuestionMark == this.hasQuestionMark && getUnsignedType() != null
|
||||||
|
|
||||||
fun IrType.getUnsignedType(): UnsignedType? =
|
fun IrType.getUnsignedType(): UnsignedType? =
|
||||||
if (this is IrSimpleType && classifier is IrClassSymbol)
|
getPrimitiveOrUnsignedType(idSignatureToUnsignedType, shortNameToUnsignedType)
|
||||||
when (classifier.signature) {
|
|
||||||
IdSignatureValues.uByte -> UnsignedType.UBYTE
|
fun <T : Enum<T>> IrType.getPrimitiveOrUnsignedType(byIdSignature: Map<IdSignature.CommonSignature, T>, byShortName: Map<Name, T>): T? {
|
||||||
IdSignatureValues.uShort -> UnsignedType.USHORT
|
if (this !is IrSimpleType) return null
|
||||||
IdSignatureValues.uInt -> UnsignedType.UINT
|
val symbol = classifier as? IrClassSymbol ?: return null
|
||||||
IdSignatureValues.uLong -> UnsignedType.ULONG
|
if (symbol.signature != null) return byIdSignature[symbol.signature]
|
||||||
else -> null
|
|
||||||
}
|
val klass = symbol.owner
|
||||||
else null
|
val parent = klass.parent
|
||||||
|
if (parent !is IrPackageFragment || parent.fqName != StandardNames.BUILT_INS_PACKAGE_FQ_NAME) return null
|
||||||
|
return byShortName[klass.name]
|
||||||
|
}
|
||||||
|
|
||||||
fun IrType.isMarkedNullable() = (this as? IrSimpleType)?.hasQuestionMark ?: false
|
fun IrType.isMarkedNullable() = (this as? IrSimpleType)?.hasQuestionMark ?: false
|
||||||
|
|
||||||
@@ -151,8 +170,6 @@ fun IrType.isLongArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignat
|
|||||||
fun IrType.isFloatArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.FLOAT]!!)
|
fun IrType.isFloatArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.FLOAT]!!)
|
||||||
fun IrType.isDoubleArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.DOUBLE]!!)
|
fun IrType.isDoubleArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.DOUBLE]!!)
|
||||||
|
|
||||||
// TODO: remove this method using FqNames.
|
|
||||||
// Need to refactor declarationBuilders.kt: visibilty is known, need to add info about package in IrFactory.buildClass (similar to name).
|
|
||||||
fun IrType.isClassType(fqName: FqNameUnsafe, hasQuestionMark: Boolean): Boolean {
|
fun IrType.isClassType(fqName: FqNameUnsafe, hasQuestionMark: Boolean): Boolean {
|
||||||
if (this !is IrSimpleType) return false
|
if (this !is IrSimpleType) return false
|
||||||
if (this.hasQuestionMark != hasQuestionMark) return false
|
if (this.hasQuestionMark != hasQuestionMark) return false
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
|||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrScriptImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrScriptImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazySymbolTable
|
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazySymbolTable
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.IrBasedClassDescriptor
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
@@ -472,7 +473,17 @@ open class SymbolTable(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun referenceClass(descriptor: ClassDescriptor): IrClassSymbol =
|
override fun referenceClass(descriptor: ClassDescriptor): IrClassSymbol =
|
||||||
classSymbolTable.referenced(descriptor) { signature -> createClassSymbol(descriptor, signature) }
|
@Suppress("Reformat")
|
||||||
|
// This is needed for cases like kt46069.kt, where psi2ir creates descriptor-less IR elements for adapted function references.
|
||||||
|
// In JVM IR, symbols are linked via descriptors by default, so for an adapted function reference, an IrBasedClassDescriptor
|
||||||
|
// is created for any classifier used in the function parameter/return types. Any attempt to translate such type to IrType goes
|
||||||
|
// to this method, which puts the descriptor into unboundClasses, which causes an assertion failure later because we won't bind
|
||||||
|
// such symbol anywhere.
|
||||||
|
// TODO: maybe there's a better solution.
|
||||||
|
if (descriptor is IrBasedClassDescriptor)
|
||||||
|
descriptor.owner.symbol
|
||||||
|
else
|
||||||
|
classSymbolTable.referenced(descriptor) { signature -> createClassSymbol(descriptor, signature) }
|
||||||
|
|
||||||
fun referenceClass(
|
fun referenceClass(
|
||||||
sig: IdSignature,
|
sig: IdSignature,
|
||||||
|
|||||||
+8
-8
@@ -154,14 +154,14 @@ abstract class KotlinIrLinker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDeclaration(symbol: IrSymbol): IrDeclaration? {
|
override fun getDeclaration(symbol: IrSymbol): IrDeclaration? =
|
||||||
if (!symbol.isPublicApi) {
|
deserializeOrResolveDeclaration(symbol, false)
|
||||||
if (symbol.hasDescriptor) {
|
|
||||||
val descriptor = symbol.descriptor
|
protected fun deserializeOrResolveDeclaration(symbol: IrSymbol, allowSymbolsWithoutSignaturesFromOtherModule: Boolean): IrDeclaration? {
|
||||||
if (!platformSpecificSymbol(symbol)) {
|
if (!allowSymbolsWithoutSignaturesFromOtherModule) {
|
||||||
if (descriptor.module !== currentModule) return null
|
if (!symbol.isPublicApi && symbol.hasDescriptor && !platformSpecificSymbol(symbol) &&
|
||||||
}
|
symbol.descriptor.module !== currentModule
|
||||||
}
|
) return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!symbol.isBound) {
|
if (!symbol.isBound) {
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.backend.jvm.serialization
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.mangle.SpecialDeclarationType
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||||
|
import org.jetbrains.kotlin.ir.util.KotlinMangler
|
||||||
|
|
||||||
|
object DisabledDescriptorMangler : KotlinMangler.DescriptorMangler {
|
||||||
|
override val String.hashMangle: Long
|
||||||
|
get() = error("Should not be called")
|
||||||
|
|
||||||
|
override fun DeclarationDescriptor.isExported(compatibleMode: Boolean): Boolean =
|
||||||
|
error("Should not be called")
|
||||||
|
|
||||||
|
override fun DeclarationDescriptor.mangleString(compatibleMode: Boolean): String =
|
||||||
|
error("Should not be called")
|
||||||
|
|
||||||
|
override fun DeclarationDescriptor.signatureString(compatibleMode: Boolean): String =
|
||||||
|
error("Should not be called")
|
||||||
|
|
||||||
|
override fun DeclarationDescriptor.fqnString(compatibleMode: Boolean): String =
|
||||||
|
error("Should not be called")
|
||||||
|
|
||||||
|
override fun ClassDescriptor.mangleEnumEntryString(compatibleMode: Boolean): String =
|
||||||
|
error("Should not be called")
|
||||||
|
|
||||||
|
override fun PropertyDescriptor.mangleFieldString(compatibleMode: Boolean): String =
|
||||||
|
error("Should not be called")
|
||||||
|
}
|
||||||
|
|
||||||
|
object DisabledIdSignatureDescriptor : IdSignatureDescriptor(DisabledDescriptorMangler) {
|
||||||
|
override fun composeSignature(descriptor: DeclarationDescriptor): IdSignature? = null
|
||||||
|
|
||||||
|
override fun composeEnumEntrySignature(descriptor: ClassDescriptor): IdSignature? = null
|
||||||
|
|
||||||
|
override fun composeFieldSignature(descriptor: PropertyDescriptor): IdSignature? = null
|
||||||
|
|
||||||
|
override fun composeAnonInitSignature(descriptor: ClassDescriptor): IdSignature? = null
|
||||||
|
|
||||||
|
override fun createSignatureBuilder(type: SpecialDeclarationType): DescriptorBasedSignatureBuilder =
|
||||||
|
error("Should not be called")
|
||||||
|
}
|
||||||
+5
-1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin
|
import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin
|
||||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||||
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
|
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
||||||
@@ -38,7 +39,8 @@ class JvmIrLinker(
|
|||||||
symbolTable: SymbolTable,
|
symbolTable: SymbolTable,
|
||||||
override val translationPluginContext: TranslationPluginContext?,
|
override val translationPluginContext: TranslationPluginContext?,
|
||||||
private val stubGenerator: DeclarationStubGenerator,
|
private val stubGenerator: DeclarationStubGenerator,
|
||||||
private val manglerDesc: JvmDescriptorMangler
|
private val manglerDesc: JvmDescriptorMangler,
|
||||||
|
private val enableIdSignatures: Boolean,
|
||||||
) : KotlinIrLinker(currentModule, messageLogger, typeSystem.irBuiltIns, symbolTable, emptyList()) {
|
) : KotlinIrLinker(currentModule, messageLogger, typeSystem.irBuiltIns, symbolTable, emptyList()) {
|
||||||
|
|
||||||
// TODO: provide friend modules
|
// TODO: provide friend modules
|
||||||
@@ -91,6 +93,8 @@ class JvmIrLinker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDeclaration(symbol: IrSymbol): IrDeclaration? =
|
||||||
|
deserializeOrResolveDeclaration(symbol, !enableIdSignatures)
|
||||||
|
|
||||||
override fun createCurrentModuleDeserializer(moduleFragment: IrModuleFragment, dependencies: Collection<IrModuleDeserializer>): IrModuleDeserializer =
|
override fun createCurrentModuleDeserializer(moduleFragment: IrModuleFragment, dependencies: Collection<IrModuleDeserializer>): IrModuleDeserializer =
|
||||||
JvmCurrentModuleDeserializer(moduleFragment, dependencies)
|
JvmCurrentModuleDeserializer(moduleFragment, dependencies)
|
||||||
|
|||||||
+5
-1
@@ -81,6 +81,8 @@ where advanced options include:
|
|||||||
-Xlambdas=indy Generate lambdas using `invokedynamic` with `LambdaMetafactory.metafactory`. Requires `-jvm-target 1.8` or greater.
|
-Xlambdas=indy Generate lambdas using `invokedynamic` with `LambdaMetafactory.metafactory`. Requires `-jvm-target 1.8` or greater.
|
||||||
Lambda objects created using `LambdaMetafactory.metafactory` will have different `toString()`.
|
Lambda objects created using `LambdaMetafactory.metafactory` will have different `toString()`.
|
||||||
-Xlambdas=class Generate lambdas as explicit classes
|
-Xlambdas=class Generate lambdas as explicit classes
|
||||||
|
-Xlink-via-signatures Link JVM IR symbols via signatures, instead of descriptors.
|
||||||
|
This mode is slower, but can be useful in troubleshooting problems with the JVM IR backend
|
||||||
-Xno-call-assertions Don't generate not-null assertions for arguments of platform types
|
-Xno-call-assertions Don't generate not-null assertions for arguments of platform types
|
||||||
-Xno-kotlin-nothing-value-exception
|
-Xno-kotlin-nothing-value-exception
|
||||||
Do not use KotlinNothingValueException available since 1.4
|
Do not use KotlinNothingValueException available since 1.4
|
||||||
@@ -133,7 +135,9 @@ where advanced options include:
|
|||||||
-Xsuppress-missing-builtins-error
|
-Xsuppress-missing-builtins-error
|
||||||
Suppress the "cannot access built-in declaration" error (useful with -no-stdlib)
|
Suppress the "cannot access built-in declaration" error (useful with -no-stdlib)
|
||||||
-Xtype-enhancement-improvements-strict-mode
|
-Xtype-enhancement-improvements-strict-mode
|
||||||
Enable strict mode for some improvements in the type enhancement for loaded Java types based on nullability annotations,including freshly supported reading of the type use annotations from class files. See KT-45671 for more details
|
Enable strict mode for some improvements in the type enhancement for loaded Java types based on nullability annotations,
|
||||||
|
including freshly supported reading of the type use annotations from class files.
|
||||||
|
See KT-45671 for more details
|
||||||
-Xuse-fast-jar-file-system Use fast implementation on Jar FS. This may speed up compilation time, but currently it's an experimental mode
|
-Xuse-fast-jar-file-system Use fast implementation on Jar FS. This may speed up compilation time, but currently it's an experimental mode
|
||||||
-Xuse-ir Use the IR backend. This option has no effect unless the language version less than 1.5 is used
|
-Xuse-ir Use the IR backend. This option has no effect unless the language version less than 1.5 is used
|
||||||
-Xuse-javac Use javac for Java source and class files analysis
|
-Xuse-javac Use javac for Java source and class files analysis
|
||||||
|
|||||||
+1
@@ -23,6 +23,7 @@ class IrInlineBodiesHandler(testServices: TestServices) : AbstractIrHandler(test
|
|||||||
override fun processModule(module: TestModule, info: IrBackendInput) {
|
override fun processModule(module: TestModule, info: IrBackendInput) {
|
||||||
val irModule = info.irModuleFragment
|
val irModule = info.irModuleFragment
|
||||||
irModule.acceptChildrenVoid(InlineFunctionsCollector())
|
irModule.acceptChildrenVoid(InlineFunctionsCollector())
|
||||||
|
assertions.assertTrue(declaredInlineFunctionSignatures.isNotEmpty())
|
||||||
irModule.acceptChildrenVoid(InlineCallBodiesCheck())
|
irModule.acceptChildrenVoid(InlineCallBodiesCheck())
|
||||||
assertions.assertTrue((info as IrBackendInput.JvmIrBackendInput).backendInput.symbolTable.allUnbound.isEmpty())
|
assertions.assertTrue((info as IrBackendInput.JvmIrBackendInput).backendInput.symbolTable.allUnbound.isEmpty())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.jvm.compiler
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||||
|
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
|
import org.jetbrains.kotlin.codegen.CodegenTestCase
|
||||||
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
|
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
|
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
|
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||||
|
import org.jetbrains.kotlin.test.TargetBackend
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
|
class JvmIrLinkageModeTest : CodegenTestCase() {
|
||||||
|
override val backend: TargetBackend
|
||||||
|
get() = TargetBackend.JVM_IR
|
||||||
|
|
||||||
|
private var enableLinkageViaSignatures: Boolean? = null
|
||||||
|
|
||||||
|
private var source = """
|
||||||
|
package test
|
||||||
|
|
||||||
|
class Class
|
||||||
|
interface Interface
|
||||||
|
sealed class Sealed<T>
|
||||||
|
enum class E { ENTRY }
|
||||||
|
|
||||||
|
fun function(s: String): Array<Int> {
|
||||||
|
fun Boolean.local() {}
|
||||||
|
return arrayOf(s.length)
|
||||||
|
}
|
||||||
|
typealias S = String
|
||||||
|
var property: S? = "OK"
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
fun testLinkageViaDescriptors() {
|
||||||
|
enableLinkageViaSignatures = false
|
||||||
|
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY)
|
||||||
|
loadText(source)
|
||||||
|
generateAndCreateClassLoader(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testLinkageViaSignatures() {
|
||||||
|
enableLinkageViaSignatures = true
|
||||||
|
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY)
|
||||||
|
loadText(source)
|
||||||
|
generateAndCreateClassLoader(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateConfiguration(configuration: CompilerConfiguration) {
|
||||||
|
super.updateConfiguration(configuration)
|
||||||
|
if (enableLinkageViaSignatures!!) {
|
||||||
|
configuration.put(JVMConfigurationKeys.LINK_VIA_SIGNATURES, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupEnvironment(environment: KotlinCoreEnvironment) {
|
||||||
|
val idSignatureShouldBePresent = environment.configuration.getBoolean(JVMConfigurationKeys.LINK_VIA_SIGNATURES)
|
||||||
|
IrGenerationExtension.registerExtension(environment.project, LinkageTestIrExtension(idSignatureShouldBePresent))
|
||||||
|
super.setupEnvironment(environment)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LinkageTestIrExtension(val idSignatureShouldBePresent: Boolean) : IrGenerationExtension {
|
||||||
|
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||||
|
val file = moduleFragment.files.single()
|
||||||
|
val signatures = mutableListOf<IdSignature>()
|
||||||
|
file.acceptVoid(object : IrElementVisitorVoid {
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclaration(declaration: IrDeclarationBase) {
|
||||||
|
super.visitDeclaration(declaration)
|
||||||
|
signatures.addIfNotNull(declaration.symbol.signature)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
val allSignatures = signatures.map { it.render().substringBefore("|") }.toSet()
|
||||||
|
if (idSignatureShouldBePresent) {
|
||||||
|
val message = allSignatures.sorted().joinToString("\n")
|
||||||
|
assertTrue(message, "test/Class" in allSignatures)
|
||||||
|
assertTrue(message, "test/Interface" in allSignatures)
|
||||||
|
assertTrue(message, "test/Sealed" in allSignatures)
|
||||||
|
assertTrue(message, "test/E" in allSignatures)
|
||||||
|
assertTrue(message, "test/function" in allSignatures)
|
||||||
|
assertTrue(message, "test/S" in allSignatures)
|
||||||
|
assertTrue(message, "test/property" in allSignatures)
|
||||||
|
assertTrue(message, "test/property.<get-property>" in allSignatures)
|
||||||
|
assertTrue(message, "test/property.<set-property>" in allSignatures)
|
||||||
|
} else {
|
||||||
|
assertEmpty(allSignatures)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user