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:
Alexander Udalov
2022-01-24 14:26:28 +01:00
parent 6e4131de8e
commit 6379fe4c4c
18 changed files with 290 additions and 70 deletions
@@ -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 {
@@ -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 ->
@@ -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!!
}
@@ -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