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(
|
||||
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," +
|
||||
"including freshly supported reading of the type use annotations from class files. " +
|
||||
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.\n" +
|
||||
"See KT-45671 for more details"
|
||||
)
|
||||
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)
|
||||
|
||||
@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> {
|
||||
val result = super.configureAnalysisFlags(collector, languageVersion)
|
||||
result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics
|
||||
|
||||
@@ -288,6 +288,8 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
|
||||
put(JVMConfigurationKeys.VALIDATE_IR, arguments.validateIr)
|
||||
put(JVMConfigurationKeys.VALIDATE_BYTECODE, arguments.validateBytecode)
|
||||
|
||||
put(JVMConfigurationKeys.LINK_VIA_SIGNATURES, arguments.linkViaSignatures)
|
||||
|
||||
val assertionsMode =
|
||||
JVMAssertionsMode.fromStringOrNull(arguments.assertionsMode)
|
||||
if (assertionsMode == null) {
|
||||
|
||||
@@ -153,4 +153,7 @@ public class JVMConfigurationKeys {
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> VALIDATE_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.path
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
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.name.FqName
|
||||
import java.util.*
|
||||
|
||||
class KtDiagnosticReporterWithImplicitIrBasedContext(
|
||||
@@ -118,7 +119,7 @@ internal class IrBasedSuppressCache : AbstractKotlinSuppressCache<IrElement>() {
|
||||
|
||||
private fun collectSuppressAnnotationKeys(element: IrElement): Boolean =
|
||||
(element as? IrAnnotationContainer)?.annotations?.filter {
|
||||
it.type.classifierOrNull?.signature == SUPPRESS
|
||||
it.type.classOrNull?.owner?.hasEqualFqName(SUPPRESS) == true
|
||||
}?.flatMap {
|
||||
buildList {
|
||||
fun addIfStringConst(irConst: IrConst<*>) {
|
||||
@@ -153,4 +154,4 @@ internal class IrBasedSuppressCache : AbstractKotlinSuppressCache<IrElement>() {
|
||||
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
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
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.util.usesDefaultArguments
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
@@ -98,7 +99,7 @@ fun collectTailRecursionCalls(irFunction: IrFunction, followFunctionReference: (
|
||||
}
|
||||
|
||||
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) {
|
||||
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.jvm.intrinsics.IrIntrinsicMethods
|
||||
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.codegen.CodegenFactory
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
@@ -73,11 +74,18 @@ open class JvmIrCodegenFactory(
|
||||
) : CodegenFactory.CodegenInput
|
||||
|
||||
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) =
|
||||
if (externalSymbolTable != null) externalMangler!! to externalSymbolTable
|
||||
else {
|
||||
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
|
||||
}
|
||||
val psi2ir = Psi2IrTranslator(input.languageVersionSettings, Psi2IrConfiguration(input.ignoreErrors))
|
||||
@@ -114,7 +122,8 @@ open class JvmIrCodegenFactory(
|
||||
symbolTable,
|
||||
frontEndContext,
|
||||
stubGenerator,
|
||||
mangler
|
||||
mangler,
|
||||
enableIdSignatures,
|
||||
)
|
||||
|
||||
val pluginContext by lazy {
|
||||
|
||||
+3
-6
@@ -121,7 +121,9 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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 =
|
||||
when (val fileEntry = this.fileEntry) {
|
||||
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.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||
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.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
@@ -43,11 +38,16 @@ internal val jvmOptimizationLoweringPhase = makeIrFilePhase(
|
||||
)
|
||||
|
||||
class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass {
|
||||
|
||||
companion object {
|
||||
fun isNegation(expression: IrExpression, context: JvmBackendContext): Boolean =
|
||||
expression is IrCall &&
|
||||
(expression.symbol as? IrPublicSymbolBase<*>)?.signature == context.irBuiltIns.booleanNotSymbol.signature
|
||||
private companion object {
|
||||
private fun isNegation(expression: IrExpression): Boolean =
|
||||
expression is IrCall && expression.symbol.owner.let { not ->
|
||||
not.name == OperatorNameConventions.NOT &&
|
||||
not.extensionReceiverParameter == null &&
|
||||
not.valueParameters.isEmpty() &&
|
||||
not.dispatchReceiverParameter.let { receiver ->
|
||||
receiver != null && receiver.type.isBoolean()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val IrFunction.isObjectEquals
|
||||
@@ -98,7 +98,7 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
return optimizePropertyAccess(expression, data)
|
||||
}
|
||||
|
||||
if (isNegation(expression, context) && isNegation(expression.dispatchReceiver!!, context)) {
|
||||
if (isNegation(expression) && isNegation(expression.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.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
@@ -144,9 +145,10 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin
|
||||
copyAttributes(reference)
|
||||
|
||||
val function = reference.symbol.owner
|
||||
val isRestricted = reference.symbol.owner.extensionReceiverParameter?.type?.classOrNull?.owner?.annotations?.any {
|
||||
it.type.classOrNull?.signature == IdSignature.CommonSignature("kotlin.coroutines", "RestrictsSuspension", null, 0)
|
||||
} == true
|
||||
val extensionReceiver = function.extensionReceiverParameter?.type?.classOrNull
|
||||
val isRestricted = extensionReceiver != null && extensionReceiver.owner.annotations.any {
|
||||
it.type.classOrNull?.isClassWithFqName(FqNameUnsafe("kotlin.coroutines.RestrictsSuspension")) == true
|
||||
}
|
||||
val suspendLambda =
|
||||
if (isRestricted) context.ir.symbols.restrictedSuspendLambdaClass.owner
|
||||
else context.ir.symbols.suspendLambdaClass.owner
|
||||
|
||||
@@ -481,22 +481,26 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
|
||||
).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
|
||||
|
||||
val signature = signature?.asPublic()
|
||||
if (signature == null || signature.packageFqName != "kotlin") return null
|
||||
|
||||
return PrimitiveType.getByShortName(signature.declarationFqName)
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.getPrimitiveArrayType(): PrimitiveType? {
|
||||
if (this !is IrClassSymbol) return null
|
||||
|
||||
val signature = signature?.asPublic()
|
||||
if (signature == null || signature.packageFqName != "kotlin") return null
|
||||
|
||||
return PrimitiveType.getByShortArrayName(signature.declarationFqName)
|
||||
return if (signature != null) {
|
||||
if (signature.packageFqName == StandardNames.BUILT_INS_PACKAGE_NAME.asString())
|
||||
signature.declarationFqName
|
||||
else null
|
||||
} else {
|
||||
val parent = owner.parent
|
||||
if (parent is IrPackageFragment && parent.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME)
|
||||
owner.name.asString()
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
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.UnsignedType
|
||||
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.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.hasEqualFqName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@Suppress("ObjectPropertyName")
|
||||
object IdSignatureValues {
|
||||
@@ -55,9 +57,14 @@ fun getPublicSignature(packageFqName: FqName, name: String) =
|
||||
private fun IrType.isClassType(signature: IdSignature.CommonSignature, hasQuestionMark: Boolean? = null): Boolean {
|
||||
if (this !is IrSimpleType) 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 =
|
||||
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())
|
||||
}
|
||||
|
||||
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> =
|
||||
PrimitiveType.values().associateWith {
|
||||
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.getPrimitiveType(): PrimitiveType? =
|
||||
if (this is IrSimpleType && classifier is IrClassSymbol)
|
||||
idSignatureToPrimitiveType[classifier.signature]
|
||||
else null
|
||||
getPrimitiveOrUnsignedType(idSignatureToPrimitiveType, shortNameToPrimitiveType)
|
||||
|
||||
fun IrType.isUnsignedType(hasQuestionMark: Boolean = false): Boolean =
|
||||
this is IrSimpleType && hasQuestionMark == this.hasQuestionMark && getUnsignedType() != null
|
||||
|
||||
fun IrType.getUnsignedType(): UnsignedType? =
|
||||
if (this is IrSimpleType && classifier is IrClassSymbol)
|
||||
when (classifier.signature) {
|
||||
IdSignatureValues.uByte -> UnsignedType.UBYTE
|
||||
IdSignatureValues.uShort -> UnsignedType.USHORT
|
||||
IdSignatureValues.uInt -> UnsignedType.UINT
|
||||
IdSignatureValues.uLong -> UnsignedType.ULONG
|
||||
else -> null
|
||||
}
|
||||
else null
|
||||
getPrimitiveOrUnsignedType(idSignatureToUnsignedType, shortNameToUnsignedType)
|
||||
|
||||
fun <T : Enum<T>> IrType.getPrimitiveOrUnsignedType(byIdSignature: Map<IdSignature.CommonSignature, T>, byShortName: Map<Name, T>): T? {
|
||||
if (this !is IrSimpleType) return null
|
||||
val symbol = classifier as? IrClassSymbol ?: return null
|
||||
if (symbol.signature != null) return byIdSignature[symbol.signature]
|
||||
|
||||
val klass = symbol.owner
|
||||
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
|
||||
|
||||
@@ -151,8 +170,6 @@ fun IrType.isLongArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignat
|
||||
fun IrType.isFloatArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.FLOAT]!!)
|
||||
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 {
|
||||
if (this !is IrSimpleType) 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.IrVariableImpl
|
||||
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.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
@@ -472,7 +473,17 @@ open class SymbolTable(
|
||||
}
|
||||
|
||||
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(
|
||||
sig: IdSignature,
|
||||
|
||||
+8
-8
@@ -154,14 +154,14 @@ abstract class KotlinIrLinker(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDeclaration(symbol: IrSymbol): IrDeclaration? {
|
||||
if (!symbol.isPublicApi) {
|
||||
if (symbol.hasDescriptor) {
|
||||
val descriptor = symbol.descriptor
|
||||
if (!platformSpecificSymbol(symbol)) {
|
||||
if (descriptor.module !== currentModule) return null
|
||||
}
|
||||
}
|
||||
override fun getDeclaration(symbol: IrSymbol): IrDeclaration? =
|
||||
deserializeOrResolveDeclaration(symbol, false)
|
||||
|
||||
protected fun deserializeOrResolveDeclaration(symbol: IrSymbol, allowSymbolsWithoutSignaturesFromOtherModule: Boolean): IrDeclaration? {
|
||||
if (!allowSymbolsWithoutSignaturesFromOtherModule) {
|
||||
if (!symbol.isPublicApi && symbol.hasDescriptor && !platformSpecificSymbol(symbol) &&
|
||||
symbol.descriptor.module !== currentModule
|
||||
) return null
|
||||
}
|
||||
|
||||
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.ir.ObsoleteDescriptorBasedAPI
|
||||
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.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
||||
@@ -38,7 +39,8 @@ class JvmIrLinker(
|
||||
symbolTable: SymbolTable,
|
||||
override val translationPluginContext: TranslationPluginContext?,
|
||||
private val stubGenerator: DeclarationStubGenerator,
|
||||
private val manglerDesc: JvmDescriptorMangler
|
||||
private val manglerDesc: JvmDescriptorMangler,
|
||||
private val enableIdSignatures: Boolean,
|
||||
) : KotlinIrLinker(currentModule, messageLogger, typeSystem.irBuiltIns, symbolTable, emptyList()) {
|
||||
|
||||
// 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 =
|
||||
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.
|
||||
Lambda objects created using `LambdaMetafactory.metafactory` will have different `toString()`.
|
||||
-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-kotlin-nothing-value-exception
|
||||
Do not use KotlinNothingValueException available since 1.4
|
||||
@@ -133,7 +135,9 @@ where advanced options include:
|
||||
-Xsuppress-missing-builtins-error
|
||||
Suppress the "cannot access built-in declaration" error (useful with -no-stdlib)
|
||||
-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-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
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ class IrInlineBodiesHandler(testServices: TestServices) : AbstractIrHandler(test
|
||||
override fun processModule(module: TestModule, info: IrBackendInput) {
|
||||
val irModule = info.irModuleFragment
|
||||
irModule.acceptChildrenVoid(InlineFunctionsCollector())
|
||||
assertions.assertTrue(declaredInlineFunctionSignatures.isNotEmpty())
|
||||
irModule.acceptChildrenVoid(InlineCallBodiesCheck())
|
||||
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