JVM IR: support value classes only when feature is enabled
Remove NeedsToVisit because it doesn't really help with performance, and it significantly increases code complexity.
This commit is contained in:
committed by
Space Team
parent
2dee47a8c1
commit
12bbdebed2
+2
@@ -176,6 +176,8 @@ fun unboxedTypeOfInlineClass(boxedType: Type, state: GenerationState): Type? {
|
||||
}
|
||||
|
||||
fun getMultiFieldValueClassUnboxInfo(boxedType: Type, state: GenerationState): MultiFieldValueClassUnboxInfo? {
|
||||
if (!state.config.supportMultiFieldValueClasses) return null
|
||||
|
||||
val descriptor =
|
||||
state.jvmBackendClassResolver.resolveToClassDescriptors(boxedType).singleOrNull()?.takeIf { it.isMultiFieldValueClass() }
|
||||
?: return null
|
||||
|
||||
+1
-1
@@ -297,7 +297,7 @@ private fun AbstractInsnNode.isInlineClassUnboxing(state: GenerationState) =
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.isMultiFieldValueClassUnboxing(state: GenerationState) =
|
||||
isMethodInsnWith(Opcodes.INVOKEVIRTUAL) {
|
||||
state.config.supportMultiFieldValueClasses && isMethodInsnWith(Opcodes.INVOKEVIRTUAL) {
|
||||
isMultiFieldValueClassUnboxingMethodDescriptor(state)
|
||||
}
|
||||
|
||||
|
||||
@@ -100,4 +100,6 @@ class JvmBackendConfig(configuration: CompilerConfiguration) {
|
||||
val noNewJavaAnnotationTargets: Boolean = configuration.getBoolean(JVMConfigurationKeys.NO_NEW_JAVA_ANNOTATION_TARGETS)
|
||||
|
||||
val oldInnerClassesLogic: Boolean = configuration.getBoolean(JVMConfigurationKeys.OLD_INNER_CLASSES_LOGIC)
|
||||
|
||||
val supportMultiFieldValueClasses: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.ValueClasses)
|
||||
}
|
||||
|
||||
+3
-1
@@ -176,7 +176,9 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
|
||||
if (check(actualTargets.defaultTargets) || check(actualTargets.canBeSubstituted) || checkWithUseSiteTargets()) {
|
||||
checkMultiFieldValueClassAnnotationRestrictions(declaration, annotation, context, reporter)
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ValueClasses)) {
|
||||
checkMultiFieldValueClassAnnotationRestrictions(declaration, annotation, context, reporter)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ open class ScopeWithIr(val scope: Scope, val irElement: IrElement)
|
||||
|
||||
abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid() {
|
||||
|
||||
protected open val scopeStack = mutableListOf<ScopeWithIr>()
|
||||
private val scopeStack = mutableListOf<ScopeWithIr>()
|
||||
|
||||
protected open fun createScope(declaration: IrSymbolOwner): ScopeWithIr =
|
||||
ScopeWithIr(Scope(declaration.symbol), declaration)
|
||||
|
||||
@@ -380,7 +380,8 @@ private val jvmFilePhases = listOf(
|
||||
forLoopsPhase,
|
||||
collectionStubMethodLowering,
|
||||
singleAbstractMethodPhase,
|
||||
jvmValueClassPhase,
|
||||
jvmMultiFieldValueClassPhase,
|
||||
jvmInlineClassPhase,
|
||||
tailrecPhase,
|
||||
// makePatchParentsPhase(),
|
||||
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ internal val bridgePhase = makeIrFilePhase(
|
||||
::BridgeLowering,
|
||||
name = "Bridge",
|
||||
description = "Generate bridges",
|
||||
prerequisite = setOf(jvmValueClassPhase, inheritedDefaultMethodsOnClassesPhase)
|
||||
prerequisite = setOf(jvmInlineClassPhase, inheritedDefaultMethodsOnClassesPhase)
|
||||
)
|
||||
|
||||
internal class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
|
||||
+14
-4
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
||||
import org.jetbrains.kotlin.backend.common.ScopeWithIr
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.*
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
@@ -29,6 +31,17 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
|
||||
|
||||
val jvmInlineClassPhase = makeIrFilePhase(
|
||||
::JvmInlineClassLowering,
|
||||
name = "InlineClasses",
|
||||
description = "Lower inline classes",
|
||||
// forLoopsPhase may produce UInt and ULong which are inline classes.
|
||||
// Standard library replacements are done on the not mangled names for UInt and ULong classes.
|
||||
// Collection stubs may require mangling by value class rules.
|
||||
// SAM wrappers may require mangling for fun interfaces with value class parameters
|
||||
prerequisite = setOf(forLoopsPhase, jvmBuiltInsPhase, collectionStubMethodLowering, singleAbstractMethodPhase),
|
||||
)
|
||||
|
||||
/**
|
||||
* Adds new constructors, box, and unbox functions to inline classes as well as replacement
|
||||
* functions and bridges to avoid clashes between overloaded function. Changes call with
|
||||
@@ -37,10 +50,7 @@ import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
|
||||
* We do not unfold inline class types here. Instead, the type mapper will lower inline class
|
||||
* types to the types of their underlying field.
|
||||
*/
|
||||
internal class JvmInlineClassLowering(
|
||||
context: JvmBackendContext,
|
||||
scopeStack: MutableList<ScopeWithIr>,
|
||||
) : JvmValueClassAbstractLowering(context, scopeStack) {
|
||||
internal class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClassAbstractLowering(context) {
|
||||
override val replacements: MemoizedValueClassAbstractReplacements
|
||||
get() = context.inlineClassReplacements
|
||||
|
||||
|
||||
+15
-5
@@ -5,9 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ScopeWithIr
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.inline
|
||||
import org.jetbrains.kotlin.backend.common.lower.irCatch
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.common.pop
|
||||
import org.jetbrains.kotlin.backend.common.push
|
||||
import org.jetbrains.kotlin.backend.jvm.*
|
||||
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.BlockOrBody.Block
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -39,10 +41,18 @@ import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
internal class JvmMultiFieldValueClassLowering(
|
||||
context: JvmBackendContext,
|
||||
scopeStack: MutableList<ScopeWithIr>,
|
||||
) : JvmValueClassAbstractLowering(context, scopeStack) {
|
||||
val jvmMultiFieldValueClassPhase = makeIrFilePhase(
|
||||
{ c: JvmBackendContext ->
|
||||
if (c.config.supportMultiFieldValueClasses)
|
||||
JvmMultiFieldValueClassLowering(c)
|
||||
else
|
||||
FileLoweringPass.Empty
|
||||
},
|
||||
name = "MultiFieldValueClasses",
|
||||
description = "Lower multi-field value classes",
|
||||
)
|
||||
|
||||
internal class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmValueClassAbstractLowering(context) {
|
||||
|
||||
private sealed class MfvcNodeInstanceAccessor {
|
||||
abstract val instance: MfvcNodeInstance
|
||||
|
||||
-1
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal abstract class JvmValueClassAbstractLowering(
|
||||
val context: JvmBackendContext,
|
||||
override val scopeStack: MutableList<ScopeWithIr>,
|
||||
) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
||||
abstract val replacements: MemoizedValueClassAbstractReplacements
|
||||
|
||||
|
||||
-225
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ScopeWithIr
|
||||
import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedValueClassLoweringDispatcherSharedData.Access.Body
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedValueClassLoweringDispatcherSharedData.Access.Header
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.typeOrNull
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
|
||||
val jvmValueClassPhase = makeIrFilePhase(
|
||||
::JvmValueClassLoweringDispatcher,
|
||||
name = "Value Classes",
|
||||
description = "Lower value classes",
|
||||
// forLoopsPhase may produce UInt and ULong which are inline classes.
|
||||
// Standard library replacements are done on the not mangled names for UInt and ULong classes.
|
||||
// Collection stubs may require mangling by value class rules.
|
||||
// SAM wrappers may require mangling for fun interfaces with value class parameters
|
||||
prerequisite = setOf(forLoopsPhase, jvmBuiltInsPhase, collectionStubMethodLowering, singleAbstractMethodPhase),
|
||||
)
|
||||
|
||||
internal class JvmValueClassLoweringDispatcher(private val context: JvmBackendContext) : IrElementTransformerVoidWithContext(),
|
||||
FileLoweringPass {
|
||||
override val scopeStack: MutableList<ScopeWithIr> = mutableListOf()
|
||||
private val inlineClassLowering: JvmInlineClassLowering = JvmInlineClassLowering(context, scopeStack)
|
||||
private val multiFieldValueClassLowering: JvmMultiFieldValueClassLowering = JvmMultiFieldValueClassLowering(context, scopeStack)
|
||||
|
||||
|
||||
override fun lower(irFile: IrFile) = withinScope(irFile) {
|
||||
irFile.transformChildrenVoid()
|
||||
}
|
||||
|
||||
override fun visitClassNew(declaration: IrClass): IrClass = if (declaration.requiresHandling()) {
|
||||
declaration
|
||||
.let(multiFieldValueClassLowering::visitClassNew)
|
||||
.let(inlineClassLowering::visitClassNew)
|
||||
} else {
|
||||
declaration
|
||||
}
|
||||
|
||||
private fun IrElement.requiresHandling(): Boolean {
|
||||
val visitor = NeedsToVisit(context)
|
||||
accept(visitor, null)
|
||||
return visitor.result
|
||||
}
|
||||
}
|
||||
|
||||
private class NeedsToVisit(private val context: JvmBackendContext) : IrElementVisitorVoid {
|
||||
var result = false
|
||||
private val replacements = context.valueClassLoweringDispatcherSharedData
|
||||
private val visitedParameters = mutableSetOf<IrSymbol>()
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
if (!result) element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
private fun IrElement.acceptAndGetResult(): Boolean {
|
||||
acceptVoid(this@NeedsToVisit)
|
||||
return result
|
||||
}
|
||||
|
||||
private val IrClass.needsHandling: Boolean
|
||||
get() = isValue || typeParameters.any { it.acceptAndGetResult() }
|
||||
private val IrType.needsHandling: Boolean
|
||||
get() = classifierOrNull?.isBound == true && erasedUpperBound.needsHandling || this is IrSimpleType && arguments.any { it.typeOrNull?.needsHandling == true }
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
visitClassHeader(declaration)
|
||||
if (result) return
|
||||
visitClassBody(declaration)
|
||||
}
|
||||
|
||||
private fun visitClassBody(declaration: IrClass) {
|
||||
if (result) return
|
||||
result = replacements.classResults.getOrPut(Body to declaration) {
|
||||
declaration.declarations.any { it.acceptAndGetResult() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitClassHeader(declaration: IrClass) {
|
||||
if (result) return
|
||||
result = replacements.classResults.getOrPut(Header to declaration) {
|
||||
declaration.needsHandling ||
|
||||
declaration.typeParameters.any { it.acceptAndGetResult() } ||
|
||||
declaration.superTypes.mapNotNull { (it.classifierOrNull as? IrClassSymbol)?.owner }.any { visitClassHeader(it); result }
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) = visitFunction(declaration, withBody = true)
|
||||
|
||||
private fun visitFunctionHeader(declaration: IrFunction) {
|
||||
if (result) return
|
||||
result = replacements.functionResults.getOrPut(Header to declaration) {
|
||||
declaration.parent.let { it is IrClass && it.needsHandling } ||
|
||||
declaration.typeParameters.any { it.acceptAndGetResult() } ||
|
||||
declaration.dispatchReceiverParameter?.acceptAndGetResult() == true ||
|
||||
declaration.extensionReceiverParameter?.acceptAndGetResult() == true ||
|
||||
declaration.valueParameters.any { it.acceptAndGetResult() } ||
|
||||
declaration.returnType.needsHandling ||
|
||||
(declaration as? IrSimpleFunction)?.overriddenSymbols?.any { visitFunction(it.owner, withBody = false); result } == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitFunction(declaration: IrFunction, withBody: Boolean) {
|
||||
visitFunctionHeader(declaration)
|
||||
if (result) return
|
||||
if(withBody) visitFunctionBody(declaration)
|
||||
}
|
||||
|
||||
private fun visitFunctionBody(declaration: IrFunction) {
|
||||
if (result) return
|
||||
result = replacements.functionResults.getOrPut(Body to declaration) {
|
||||
declaration.body?.acceptAndGetResult() == true
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitValueParameter(declaration: IrValueParameter) {
|
||||
if (result || !visitedParameters.add(declaration.symbol)) return
|
||||
result = declaration.type.needsHandling
|
||||
if (result) return
|
||||
super.visitValueParameter(declaration)
|
||||
}
|
||||
|
||||
override fun visitTypeParameter(declaration: IrTypeParameter) {
|
||||
if (result || !visitedParameters.add(declaration.symbol)) return
|
||||
result = declaration.superTypes.any { it.needsHandling }
|
||||
if (result) return
|
||||
super.visitTypeParameter(declaration)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||
if (result) return
|
||||
visitFunction(expression.symbol.owner, withBody = false)
|
||||
if (result) return
|
||||
super.visitFunctionReference(expression)
|
||||
}
|
||||
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
|
||||
if (result) return
|
||||
visitFunction(expression.symbol.owner, withBody = false)
|
||||
if (result) return
|
||||
super.visitFunctionAccess(expression)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) = visitField(declaration, withBody = true)
|
||||
|
||||
private fun visitFieldHeader(declaration: IrField) {
|
||||
if (result) return
|
||||
result = replacements.fieldResults.getOrPut(Header to declaration) {
|
||||
declaration.type.needsHandling
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitFieldBody(declaration: IrField) {
|
||||
if (result) return
|
||||
result = replacements.fieldResults.getOrPut(Body to declaration) {
|
||||
super.visitField(declaration)
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitField(declaration: IrField, withBody: Boolean) {
|
||||
visitFieldHeader(declaration)
|
||||
if (withBody) visitFieldBody(declaration)
|
||||
}
|
||||
|
||||
override fun visitFieldAccess(expression: IrFieldAccessExpression) {
|
||||
if (result) return
|
||||
visitField(expression.symbol.owner, withBody = false)
|
||||
if (result) return
|
||||
super.visitFieldAccess(expression)
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
if (result) return
|
||||
result = declaration.type.needsHandling
|
||||
if (result) return
|
||||
super.visitVariable(declaration)
|
||||
}
|
||||
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation) {
|
||||
if (result) return
|
||||
result = expression.arguments.any { it.type.needsHandling }
|
||||
if (result) return
|
||||
super.visitStringConcatenation(expression)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
if (result) return
|
||||
if (expression.symbol == context.irBuiltIns.eqeqSymbol) {
|
||||
for (it in 0 until expression.valueArgumentsCount) {
|
||||
result = expression.getValueArgument(it)?.type?.needsHandling ?: false
|
||||
if (result) return
|
||||
}
|
||||
}
|
||||
super.visitCall(expression)
|
||||
}
|
||||
|
||||
override fun visitExpression(expression: IrExpression) {
|
||||
if (result) return
|
||||
result = expression.type.needsHandling
|
||||
if (result) return
|
||||
super.visitExpression(expression)
|
||||
}
|
||||
}
|
||||
@@ -185,8 +185,6 @@ class JvmBackendContext(
|
||||
|
||||
val multiFieldValueClassReplacements = MemoizedMultiFieldValueClassReplacements(irFactory, this)
|
||||
|
||||
val valueClassLoweringDispatcherSharedData = MemoizedValueClassLoweringDispatcherSharedData()
|
||||
|
||||
val continuationClassesVarsCountByType: MutableMap<IrAttributeContainer, Map<Type, Int>> = hashMapOf()
|
||||
|
||||
val inlineMethodGenerationLock = Any()
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
class MemoizedValueClassLoweringDispatcherSharedData {
|
||||
enum class Access { Header, Body }
|
||||
|
||||
val functionResults: ConcurrentMap<Pair<Access, IrFunction>, Boolean> = ConcurrentHashMap()
|
||||
val classResults: ConcurrentMap<Pair<Access, IrClass>, Boolean> = ConcurrentHashMap()
|
||||
val fieldResults: ConcurrentMap<Pair<Access, IrField>, Boolean> = ConcurrentHashMap()
|
||||
}
|
||||
Reference in New Issue
Block a user