JVM IR: extract lowerings to a separate module

Together with extracting codegen to a separate (unrelated) module in the
future, hopefully it'll speed up the build of JVM IR by making it more
parallel, and helping incremental compilation to avoid recompiling code
that depends on lowerings because of `implementation` dependency.
This commit is contained in:
Alexander Udalov
2021-09-10 12:54:30 +02:00
parent eee8b033a6
commit 7efc9dac9b
80 changed files with 60 additions and 35 deletions
+1
View File
@@ -238,6 +238,7 @@ val fe10CompilerModules = arrayOf(
":compiler:frontend:cfg",
":compiler:ir.psi2ir",
":compiler:backend.jvm",
":compiler:backend.jvm.lower",
":compiler:backend.jvm:backend.jvm.entrypoint",
":compiler:backend.js",
":compiler:backend.wasm",
+1
View File
@@ -12,6 +12,7 @@ dependencies {
compile(project(":compiler:backend-common"))
compile(project(":compiler:backend"))
compile(project(":compiler:backend.jvm"))
implementation(project(":compiler:backend.jvm.lower"))
implementation(project(":compiler:backend.jvm:backend.jvm.entrypoint"))
compile(project(":compiler:ir.backend.common"))
compile(project(":compiler:light-classes"))
-1
View File
@@ -11,7 +11,6 @@ dependencies {
api(project(":compiler:backend.common.jvm"))
compileOnly(project(":compiler:ir.tree.impl"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "asm-all", "guava", rootProject = rootProject) }
compileOnly(intellijDep()) { includeJars("trove4j", rootProject = rootProject) }
}
sourceSets {
@@ -8,6 +8,7 @@ dependencies {
api(project(":compiler:backend.jvm"))
api(project(":compiler:ir.tree.impl"))
api(project(":compiler:ir.serialization.jvm"))
implementation(project(":compiler:backend.jvm.lower"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
}
@@ -0,0 +1,20 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
api(project(":compiler:ir.tree"))
api(project(":compiler:ir.backend.common"))
api(project(":compiler:backend.jvm"))
implementation(project(":compiler:ir.tree.impl"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
compileOnly(intellijDep()) { includeJars("trove4j", rootProject = rootProject) }
}
sourceSets {
"main" {
projectDefault()
}
"test" {}
}
@@ -275,7 +275,7 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
// Deal with existing function that override special bridge methods.
if (!irFunction.isFakeOverride && specialBridge.methodInfo != null) {
irFunction.rewriteSpecialMethodBody(targetMethod, specialBridge.signature, specialBridge.methodInfo)
irFunction.rewriteSpecialMethodBody(targetMethod, specialBridge.signature, specialBridge.methodInfo!!)
}
// For generic special bridge methods we need to generate bridges for generic overrides coming from Java or Kotlin interfaces.
@@ -95,7 +95,7 @@ private class MoveOrCopyCompanionObjectFieldsLowering(val context: JvmBackendCon
private val IrProperty.hasPublicVisibility: Boolean
get() = !DescriptorVisibilities.isPrivate(visibility) && visibility != DescriptorVisibilities.PROTECTED
private fun makeAnonymousInitializerStatic(oldInitializer: IrAnonymousInitializer, newParent: IrClass) =
private fun makeAnonymousInitializerStatic(oldInitializer: IrAnonymousInitializer, newParent: IrClass): IrAnonymousInitializer =
with(oldInitializer) {
val oldParent = parentAsClass
val newSymbol = IrAnonymousInitializerSymbolImpl(newParent.symbol)
@@ -243,7 +243,7 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) {
private fun IrClass.addSimplePropertyFrom(
from: IrValueDeclaration,
initializer: IrExpressionBodyImpl? = null
initializer: IrExpressionBody? = null
) {
addProperty {
updateFrom(from)
@@ -37,7 +37,7 @@ object InlineClassAbi {
* Unwraps inline class types to their underlying representation.
* Returns null if the type cannot be unboxed.
*/
internal fun unboxType(type: IrType): IrType? {
fun unboxType(type: IrType): IrType? {
val klass = type.classOrNull?.owner ?: return null
val representation = klass.inlineClassRepresentation ?: return null
@@ -118,24 +118,24 @@ object InlineClassAbi {
get() = (this as IrSimpleFunction).correspondingPropertySymbol!!.owner.name
}
internal val IrType.requiresMangling: Boolean
val IrType.requiresMangling: Boolean
get() {
val irClass = erasedUpperBound
return irClass.isInline && irClass.fqNameWhenAvailable != StandardNames.RESULT_FQ_NAME
}
internal val IrFunction.fullValueParameterList: List<IrValueParameter>
val IrFunction.fullValueParameterList: List<IrValueParameter>
get() = listOfNotNull(extensionReceiverParameter) + valueParameters
internal val IrFunction.hasMangledParameters: Boolean
val IrFunction.hasMangledParameters: Boolean
get() = dispatchReceiverParameter != null && parentAsClass.isInline ||
fullValueParameterList.any { it.type.requiresMangling } ||
(this is IrConstructor && constructedClass.isInline)
internal val IrFunction.hasMangledReturnType: Boolean
val IrFunction.hasMangledReturnType: Boolean
get() = returnType.isInlineClassType() && parentClassOrNull?.isFileClass != true
internal val IrClass.inlineClassFieldName: Name
val IrClass.inlineClassFieldName: Name
get() = (inlineClassRepresentation ?: error("Not an inline class: ${render()}")).underlyingPropertyName
val IrFunction.isInlineClassFieldGetter: Boolean
@@ -65,8 +65,8 @@ class JvmBackendContext(
val typeMapper = IrTypeMapper(this)
val methodSignatureMapper = MethodSignatureMapper(this)
internal val innerClassesSupport = JvmInnerClassesSupport(irFactory)
internal val cachedDeclarations = JvmCachedDeclarations(
val innerClassesSupport = JvmInnerClassesSupport(irFactory)
val cachedDeclarations = JvmCachedDeclarations(
this, generatorExtensions.cachedFields
)
@@ -82,27 +82,27 @@ class JvmBackendContext(
private val localClassType = ConcurrentHashMap<IrAttributeContainer, Type>()
internal fun getLocalClassType(container: IrAttributeContainer): Type? =
fun getLocalClassType(container: IrAttributeContainer): Type? =
localClassType[container.attributeOwnerId]
internal fun putLocalClassType(container: IrAttributeContainer, value: Type) {
fun putLocalClassType(container: IrAttributeContainer, value: Type) {
localClassType[container.attributeOwnerId] = value
}
internal val isEnclosedInConstructor = ConcurrentHashMap.newKeySet<IrAttributeContainer>()
val isEnclosedInConstructor = ConcurrentHashMap.newKeySet<IrAttributeContainer>()
internal val classCodegens = ConcurrentHashMap<IrClass, ClassCodegen>()
val localDelegatedProperties = ConcurrentHashMap<IrAttributeContainer, List<IrLocalDelegatedPropertySymbol>>()
internal val multifileFacadesToAdd = mutableMapOf<JvmClassName, MutableList<IrClass>>()
val multifileFacadesToAdd = mutableMapOf<JvmClassName, MutableList<IrClass>>()
val multifileFacadeForPart = mutableMapOf<IrClass, JvmClassName>()
internal val multifileFacadeClassForPart = mutableMapOf<IrClass, IrClass>()
internal val multifileFacadeMemberToPartMember = mutableMapOf<IrSimpleFunction, IrSimpleFunction>()
val multifileFacadeClassForPart = mutableMapOf<IrClass, IrClass>()
val multifileFacadeMemberToPartMember = mutableMapOf<IrSimpleFunction, IrSimpleFunction>()
internal val hiddenConstructors = ConcurrentHashMap<IrConstructor, IrConstructor>()
val hiddenConstructors = ConcurrentHashMap<IrConstructor, IrConstructor>()
internal val collectionStubComputer = CollectionStubComputer(this)
val collectionStubComputer = CollectionStubComputer(this)
private val overridesWithoutStubs = HashMap<IrSimpleFunction, List<IrSimpleFunctionSymbol>>()
@@ -113,8 +113,8 @@ class JvmBackendContext(
fun getOverridesWithoutStubs(function: IrSimpleFunction): List<IrSimpleFunctionSymbol> =
overridesWithoutStubs.getOrElse(function) { function.overriddenSymbols }
internal val bridgeLoweringCache = BridgeLoweringCache(this)
internal val functionsWithSpecialBridges: MutableSet<IrFunction> = ConcurrentHashMap.newKeySet()
val bridgeLoweringCache = BridgeLoweringCache(this)
val functionsWithSpecialBridges: MutableSet<IrFunction> = ConcurrentHashMap.newKeySet()
override var inVerbosePhase: Boolean = false // TODO: needs parallelizing
@@ -130,7 +130,7 @@ class JvmBackendContext(
val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory, this)
internal val continuationClassesVarsCountByType: MutableMap<IrAttributeContainer, Map<Type, Int>> = hashMapOf()
val continuationClassesVarsCountByType: MutableMap<IrAttributeContainer, Map<Type, Int>> = hashMapOf()
val inlineMethodGenerationLock = Any()
@@ -44,7 +44,7 @@ class MemoizedInlineClassReplacements(
private val storageManager = LockBasedStorageManager("inline-class-replacements")
private val propertyMap = ConcurrentHashMap<IrPropertySymbol, IrProperty>()
internal val originalFunctionForStaticReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
val originalFunctionForStaticReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
internal val originalFunctionForMethodReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
/**
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.org.objectweb.asm.commons.Method
import java.util.concurrent.ConcurrentHashMap
internal class BridgeLoweringCache(private val context: JvmBackendContext) {
class BridgeLoweringCache(private val context: JvmBackendContext) {
private val specialBridgeMethods = SpecialBridgeMethods(context)
// TODO: consider moving this cache out to the backend context and using it everywhere throughout the codegen.
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.ir.util.isFromJava
import org.jetbrains.kotlin.ir.util.parentAsClass
import java.util.concurrent.ConcurrentHashMap
internal class CollectionStubComputer(val context: JvmBackendContext) {
class CollectionStubComputer(val context: JvmBackendContext) {
private class LazyStubsForCollectionClass(
override val readOnlyClass: IrClassSymbol,
override val mutableClass: IrClassSymbol
@@ -450,7 +450,7 @@ private fun isBareTypeParameterWithNullableUpperBound(type: IrType): Boolean {
private val RETENTION_PARAMETER_NAME = Name.identifier("value")
internal fun IrClass.getAnnotationRetention(): KotlinRetention? {
fun IrClass.getAnnotationRetention(): KotlinRetention? {
val retentionArgument =
getAnnotation(StandardNames.FqNames.retention)?.getValueArgument(RETENTION_PARAMETER_NAME)
as? IrGetEnumValue ?: return null
@@ -108,7 +108,7 @@ internal fun IrFunction.continuationClass(): IrClass? =
(body as? IrBlockBody)?.statements?.find { it is IrClass && it.origin == JvmLoweredDeclarationOrigin.CONTINUATION_CLASS }
as IrClass?
internal fun IrFunction.continuationParameter(): IrValueParameter? = when {
fun IrFunction.continuationParameter(): IrValueParameter? = when {
isInvokeSuspendOfLambda() || isInvokeSuspendForInlineOfLambda() -> dispatchReceiverParameter
else -> valueParameters.singleOrNull { it.origin == JvmLoweredDeclarationOrigin.CONTINUATION_CLASS }
}
@@ -120,7 +120,7 @@ private fun IrFunction.isInvokeSuspendForInlineOfLambda(): Boolean =
origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE
&& parentAsClass.origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA
internal fun IrFunction.isInvokeSuspendOfContinuation(): Boolean =
fun IrFunction.isInvokeSuspendOfContinuation(): Boolean =
name.asString() == INVOKE_SUSPEND_METHOD_NAME && parentAsClass.origin == JvmLoweredDeclarationOrigin.CONTINUATION_CLASS
private fun IrFunction.isInvokeOfSuspendCallableReference(): Boolean =
@@ -155,7 +155,7 @@ private val BRIDGE_ORIGINS = setOf(
internal fun IrFunction.isNonBoxingSuspendDelegation(): Boolean =
origin in BRIDGE_ORIGINS || isMultifileBridge() || isBridgeToSuspendImplMethod()
internal fun IrFunction.shouldContainSuspendMarkers(): Boolean = !isNonBoxingSuspendDelegation() &&
fun IrFunction.shouldContainSuspendMarkers(): Boolean = !isNonBoxingSuspendDelegation() &&
// These functions also contain a single `suspend` tail call, but if it returns an unboxed inline class value,
// the return of it should be checked for a suspension and potentially boxed to satisfy an interface.
origin != IrDeclarationOrigin.DELEGATED_MEMBER &&
@@ -163,7 +163,7 @@ internal fun IrFunction.shouldContainSuspendMarkers(): Boolean = !isNonBoxingSus
!isInvokeOfSuspendCallableReference() &&
!isStaticInlineClassReplacementDelegatingCall()
internal fun IrFunction.hasContinuation(): Boolean = isInvokeSuspendOfLambda() ||
fun IrFunction.hasContinuation(): Boolean = isInvokeSuspendOfLambda() ||
isSuspend && shouldContainSuspendMarkers() &&
// These are templates for the inliner; the continuation is borrowed from the caller method.
!isEffectivelyInlineOnly() &&
@@ -171,7 +171,7 @@ internal fun IrFunction.hasContinuation(): Boolean = isInvokeSuspendOfLambda() |
origin != JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE &&
origin != JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE
internal fun IrExpression?.isReadOfCrossinline(): Boolean = when (this) {
fun IrExpression?.isReadOfCrossinline(): Boolean = when (this) {
is IrGetValue -> (symbol.owner as? IrValueParameter)?.isCrossinline == true
is IrGetField -> symbol.owner.origin == LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE
else -> false
@@ -308,7 +308,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
// Boxing is only necessary for 'remove(E): Boolean' of a MutableCollection<Int> implementation.
// Otherwise this method might clash with 'remove(I): E' defined in the java.util.List JDK interface (mapped to kotlin 'removeAt').
internal fun shouldBoxSingleValueParameterForSpecialCaseOfRemove(irFunction: IrFunction): Boolean {
fun shouldBoxSingleValueParameterForSpecialCaseOfRemove(irFunction: IrFunction): Boolean {
if (irFunction !is IrSimpleFunction) return false
if (irFunction.name.asString() != "remove" && !irFunction.name.asString().startsWith("remove-")) return false
if (irFunction.isFromJava()) return false
@@ -425,7 +425,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
return null
}
internal fun mapCalleeToAsmMethod(function: IrSimpleFunction, isSuperCall: Boolean = false): Method =
fun mapCalleeToAsmMethod(function: IrSimpleFunction, isSuperCall: Boolean = false): Method =
mapAsmMethod(findSuperDeclaration(function, isSuperCall))
// Copied from KotlinTypeMapper.findSuperDeclaration.
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
internal open class IrInlineReferenceLocator(private val context: JvmBackendContext) : IrElementVisitor<Unit, IrDeclaration?> {
open class IrInlineReferenceLocator(private val context: JvmBackendContext) : IrElementVisitor<Unit, IrDeclaration?> {
override fun visitElement(element: IrElement, data: IrDeclaration?) {
element.acceptChildren(this, data)
}
@@ -9,6 +9,7 @@ dependencies {
testApi(project(":compiler:fir:entrypoint"))
testApi(project(":compiler:cli"))
testImplementation(project(":compiler:ir.tree.impl"))
testImplementation(project(":compiler:backend.jvm.lower"))
testImplementation(project(":compiler:backend.jvm:backend.jvm.entrypoint"))
testImplementation(intellijCoreDep()) { includeJars("intellij-core") }
+2
View File
@@ -116,6 +116,7 @@ include ":benchmarks",
":compiler:backend.js",
":compiler:backend.wasm",
":compiler:backend.jvm",
":compiler:backend.jvm.lower",
":compiler:backend.jvm:backend.jvm.entrypoint",
":compiler:backend-common",
":compiler:backend",
@@ -538,6 +539,7 @@ project(':compiler:ir.backend.common').projectDir = "$rootDir/compiler/ir/backen
project(':compiler:backend.js').projectDir = "$rootDir/compiler/ir/backend.js" as File
project(':compiler:backend.wasm').projectDir = "$rootDir/compiler/ir/backend.wasm" as File
project(':compiler:backend.jvm').projectDir = "$rootDir/compiler/ir/backend.jvm" as File
project(':compiler:backend.jvm.lower').projectDir = "$rootDir/compiler/ir/backend.jvm/lower" as File
project(':compiler:backend.jvm:backend.jvm.entrypoint').projectDir = "$rootDir/compiler/ir/backend.jvm/entrypoint" as File
project(':compiler:ir.serialization.common').projectDir = "$rootDir/compiler/ir/serialization.common" as File
project(':compiler:ir.serialization.jvm').projectDir = "$rootDir/compiler/ir/serialization.jvm" as File