[IR] Change value classes lowering dispatching strategy
Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com> #KT-1179
This commit is contained in:
committed by
Space Team
parent
c1ac580031
commit
2535a87f85
+6
@@ -52149,6 +52149,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
|
||||
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedLoweringStart.kt")
|
||||
public void testNestedLoweringStart() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/valueClasses/nestedLoweringStart.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nothingAsParameterType.kt")
|
||||
public void testNothingAsParameterType() throws Exception {
|
||||
|
||||
+6
@@ -52149,6 +52149,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
|
||||
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedLoweringStart.kt")
|
||||
public void testNestedLoweringStart() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/valueClasses/nestedLoweringStart.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nothingAsParameterType.kt")
|
||||
public void testNothingAsParameterType() throws Exception {
|
||||
|
||||
-2
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.jvm.*
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
@@ -72,7 +71,6 @@ internal class JvmInlineClassLowering(
|
||||
|
||||
override val specificMangle: SpecificMangle
|
||||
get() = SpecificMangle.Inline
|
||||
override val IrType.needsHandling get() = isInlineClassType()
|
||||
override fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration) = Unit
|
||||
|
||||
override fun visitClassNew(declaration: IrClass): IrClass {
|
||||
|
||||
-2
@@ -46,8 +46,6 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
context: JvmBackendContext,
|
||||
scopeStack: MutableList<ScopeWithIr>,
|
||||
) : JvmValueClassAbstractLowering(context, scopeStack) {
|
||||
override val IrType.needsHandling: Boolean
|
||||
get() = needsMfvcFlattening()
|
||||
|
||||
private sealed class MfvcNodeInstanceAccessor {
|
||||
abstract val instance: MfvcNodeInstance
|
||||
|
||||
+3
-64
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.*
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isValueClassType
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
@@ -15,6 +16,8 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.transformStatement
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
@@ -243,68 +246,6 @@ internal abstract class JvmValueClassAbstractLowering(
|
||||
protected abstract fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction, original: IrFunction, inverted: Boolean)
|
||||
|
||||
|
||||
// Functions for common lowering dispatching
|
||||
private inner class NeedsToVisit : IrElementVisitor<Boolean, Nothing?> {
|
||||
override fun visitElement(element: IrElement, data: Nothing?): Boolean = false
|
||||
override fun visitClass(declaration: IrClass, data: Nothing?): Boolean =
|
||||
declaration.isSpecificLoweringLogicApplicable() || declaration.declarations.any { it.accept(this, null) }
|
||||
|
||||
override fun visitFunction(declaration: IrFunction, data: Nothing?): Boolean =
|
||||
replacements.quickCheckIfFunctionIsNotApplicable(declaration)
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean =
|
||||
visitFunction(expression.symbol.owner, data)
|
||||
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: Nothing?): Boolean =
|
||||
visitFunction(expression.symbol.owner, data)
|
||||
|
||||
override fun visitField(declaration: IrField, data: Nothing?): Boolean = declaration.type.needsHandling
|
||||
override fun visitFieldAccess(expression: IrFieldAccessExpression, data: Nothing?): Boolean =
|
||||
visitField(expression.symbol.owner, data)
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, data: Nothing?): Boolean = visitValueDeclaration(declaration)
|
||||
|
||||
private fun visitValueDeclaration(declaration: IrValueDeclaration) = declaration.type.needsHandling
|
||||
override fun visitValueParameter(declaration: IrValueParameter, data: Nothing?): Boolean = visitValueDeclaration(declaration)
|
||||
override fun visitValueAccess(expression: IrValueAccessExpression, data: Nothing?): Boolean =
|
||||
visitValueDeclaration(expression.symbol.owner)
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): Boolean = false
|
||||
override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean = (expression.returnTargetSymbol.owner as? IrFunction)
|
||||
?.let { replacements.quickCheckIfFunctionIsNotApplicable(it) } ?: false
|
||||
|
||||
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?): Boolean =
|
||||
(declaration.parent as? IrClass)?.isSpecificLoweringLogicApplicable() == true
|
||||
|
||||
private fun visitStatementContainer(container: IrStatementContainer) = container.statements.any { it.accept(this, null) }
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression, data: Nothing?): Boolean =
|
||||
visitStatementContainer(expression)
|
||||
|
||||
override fun visitBlockBody(body: IrBlockBody, data: Nothing?): Boolean = visitStatementContainer(body)
|
||||
}
|
||||
|
||||
internal fun needsToVisitClassNew(declaration: IrClass): Boolean = declaration.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitFunctionReference(expression: IrFunctionReference): Boolean = expression.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitFunctionAccess(expression: IrFunctionAccessExpression): Boolean = expression.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitCall(expression: IrCall): Boolean = expression.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitStringConcatenation(expression: IrStringConcatenation): Boolean = expression.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitGetField(expression: IrGetField): Boolean = expression.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitSetField(expression: IrSetField): Boolean = expression.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitGetValue(expression: IrGetValue): Boolean = expression.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitSetValue(expression: IrSetValue): Boolean = expression.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitVariable(declaration: IrVariable): Boolean = declaration.accept(NeedsToVisit(), null)
|
||||
|
||||
internal fun needsToVisitReturn(expression: IrReturn): Boolean = expression.accept(NeedsToVisit(), null)
|
||||
internal abstract fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration)
|
||||
|
||||
// forbid other overrides without modifying dispatcher file JvmValueClassLoweringDispatcher.kt
|
||||
@@ -380,6 +321,4 @@ internal abstract class JvmValueClassAbstractLowering(
|
||||
final override fun visitErrorExpression(expression: IrErrorExpression) = super.visitErrorExpression(expression)
|
||||
final override fun visitErrorCallExpression(expression: IrErrorCallExpression) = super.visitErrorCallExpression(expression)
|
||||
|
||||
|
||||
abstract val IrType.needsHandling: Boolean
|
||||
}
|
||||
|
||||
+146
-120
@@ -11,15 +11,21 @@ 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.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.transformStatement
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
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,
|
||||
@@ -32,7 +38,8 @@ val jvmValueClassPhase = makeIrFilePhase(
|
||||
prerequisite = setOf(forLoopsPhase, jvmBuiltInsPhase, collectionStubMethodLowering, singleAbstractMethodPhase),
|
||||
)
|
||||
|
||||
internal class JvmValueClassLoweringDispatcher(context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||
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)
|
||||
@@ -42,158 +49,177 @@ internal class JvmValueClassLoweringDispatcher(context: JvmBackendContext) : IrE
|
||||
irFile.transformChildrenVoid()
|
||||
}
|
||||
|
||||
|
||||
private fun IrElement.requiresAnyHandling() =
|
||||
requiresHandling(multiFieldValueClassLowering) || requiresHandling(inlineClassLowering)
|
||||
|
||||
override fun visitClassNew(declaration: IrClass): IrClass = if (declaration.requiresAnyHandling()) {
|
||||
override fun visitClassNew(declaration: IrClass): IrClass = if (declaration.requiresHandling()) {
|
||||
declaration
|
||||
.let(multiFieldValueClassLowering::visitClassNew)
|
||||
.let(inlineClassLowering::visitClassNew)
|
||||
} else {
|
||||
declaration.transformChildrenVoid()
|
||||
for (innerDeclaration in declaration.declarations) {
|
||||
multiFieldValueClassLowering.visitClassNewDeclarationsWhenParallel(innerDeclaration)
|
||||
}
|
||||
for (innerDeclaration in declaration.declarations) {
|
||||
inlineClassLowering.visitClassNewDeclarationsWhenParallel(innerDeclaration)
|
||||
}
|
||||
declaration
|
||||
}
|
||||
|
||||
private fun transformExpressionConsequently(expression: IrExpression) = expression
|
||||
.transform(multiFieldValueClassLowering, null)
|
||||
.transform(inlineClassLowering, null)
|
||||
private fun IrElement.requiresHandling(): Boolean {
|
||||
val visitor = NeedsToVisit(context)
|
||||
accept(visitor, null)
|
||||
return visitor.result
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformStatementConsequently(statement: IrStatement) = statement
|
||||
.transformStatement(multiFieldValueClassLowering)
|
||||
.transformStatement(inlineClassLowering)
|
||||
private class NeedsToVisit(private val context: JvmBackendContext) : IrElementVisitorVoid {
|
||||
var result = false
|
||||
private val replacements = context.valueClassLoweringDispatcherSharedData
|
||||
private val visitedParameters = mutableSetOf<IrSymbol>()
|
||||
|
||||
private fun IrElement.requiresHandling(lowering: JvmValueClassAbstractLowering) =
|
||||
accept(object : IrElementVisitor<Boolean, Nothing?> {
|
||||
override fun visitElement(element: IrElement, data: Nothing?): Boolean = false
|
||||
override fun visitClass(declaration: IrClass, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitClassNew(declaration) || super.visitClass(declaration, data)
|
||||
override fun visitElement(element: IrElement) {
|
||||
if (!result) element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitFunctionReference(expression) || super.visitFunctionReference(expression, data)
|
||||
private fun IrElement.acceptAndGetResult(): Boolean {
|
||||
acceptVoid(this@NeedsToVisit)
|
||||
return result
|
||||
}
|
||||
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitFunctionAccess(expression) || super.visitFunctionAccess(expression, data)
|
||||
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 visitCall(expression: IrCall, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitCall(expression) || super.visitCall(expression, data)
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
visitClassHeader(declaration)
|
||||
if (result) return
|
||||
visitClassBody(declaration)
|
||||
}
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitStringConcatenation(expression) || super.visitStringConcatenation(expression, data)
|
||||
private fun visitClassBody(declaration: IrClass) {
|
||||
if (result) return
|
||||
result = replacements.classResults.getOrPut(Body to declaration) {
|
||||
declaration.declarations.any { it.acceptAndGetResult() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGetField(expression: IrGetField, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitGetField(expression) || super.visitGetField(expression, data)
|
||||
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 visitSetField(expression: IrSetField, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitSetField(expression) || super.visitSetField(expression, data)
|
||||
override fun visitFunction(declaration: IrFunction) = visitFunction(declaration, withBody = true)
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitGetValue(expression) || super.visitGetValue(expression, data)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitSetValue(expression: IrSetValue, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitSetValue(expression) || super.visitSetValue(expression, data)
|
||||
private fun visitFunction(declaration: IrFunction, withBody: Boolean) {
|
||||
visitFunctionHeader(declaration)
|
||||
if (result) return
|
||||
if(withBody) visitFunctionBody(declaration)
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitVariable(declaration) || super.visitVariable(declaration, data)
|
||||
private fun visitFunctionBody(declaration: IrFunction) {
|
||||
if (result) return
|
||||
result = replacements.functionResults.getOrPut(Body to declaration) {
|
||||
declaration.body?.acceptAndGetResult() == true
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitReturn(expression) || super.visitReturn(expression, data)
|
||||
override fun visitValueParameter(declaration: IrValueParameter) {
|
||||
if (result || !visitedParameters.add(declaration.symbol)) return
|
||||
result = declaration.type.needsHandling
|
||||
if (result) return
|
||||
super.visitValueParameter(declaration)
|
||||
}
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression, data: Nothing?): Boolean =
|
||||
visitStatementContainer(expression)
|
||||
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 visitBlockBody(body: IrBlockBody, data: Nothing?): Boolean =
|
||||
visitStatementContainer(body)
|
||||
|
||||
private fun visitStatementContainer(expression: IrStatementContainer) = expression.statements.any { it.accept(this, null) }
|
||||
}, null)
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression = if (expression.requiresAnyHandling()) {
|
||||
transformExpressionConsequently(expression)
|
||||
} else {
|
||||
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): IrExpression = if (expression.requiresAnyHandling()) {
|
||||
transformExpressionConsequently(expression)
|
||||
} else {
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
|
||||
if (result) return
|
||||
visitFunction(expression.symbol.owner, withBody = false)
|
||||
if (result) return
|
||||
super.visitFunctionAccess(expression)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression = if (expression.requiresAnyHandling()) {
|
||||
transformExpressionConsequently(expression)
|
||||
} else {
|
||||
super.visitCall(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
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression = if (expression.requiresAnyHandling()) {
|
||||
transformExpressionConsequently(expression)
|
||||
} else {
|
||||
super.visitStringConcatenation(expression)
|
||||
private fun visitFieldBody(declaration: IrField) {
|
||||
if (result) return
|
||||
result = replacements.fieldResults.getOrPut(Body to declaration) {
|
||||
super.visitField(declaration)
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGetField(expression: IrGetField): IrExpression = if (expression.requiresAnyHandling()) {
|
||||
transformExpressionConsequently(expression)
|
||||
} else {
|
||||
super.visitGetField(expression)
|
||||
private fun visitField(declaration: IrField, withBody: Boolean) {
|
||||
visitFieldHeader(declaration)
|
||||
if (withBody) visitFieldBody(declaration)
|
||||
}
|
||||
|
||||
override fun visitSetField(expression: IrSetField): IrExpression = if (expression.requiresAnyHandling()) {
|
||||
transformExpressionConsequently(expression)
|
||||
} else {
|
||||
super.visitSetField(expression)
|
||||
override fun visitFieldAccess(expression: IrFieldAccessExpression) {
|
||||
if (result) return
|
||||
visitField(expression.symbol.owner, withBody = false)
|
||||
if (result) return
|
||||
super.visitFieldAccess(expression)
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression = if (expression.requiresAnyHandling()) {
|
||||
transformExpressionConsequently(expression)
|
||||
} else {
|
||||
super.visitGetValue(expression)
|
||||
}
|
||||
|
||||
override fun visitSetValue(expression: IrSetValue): IrExpression = if (expression.requiresAnyHandling()) {
|
||||
transformExpressionConsequently(expression)
|
||||
} else {
|
||||
super.visitSetValue(expression)
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable): IrStatement = if (declaration.requiresAnyHandling()) {
|
||||
transformStatementConsequently(declaration)
|
||||
} else {
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
if (result) return
|
||||
result = declaration.type.needsHandling
|
||||
if (result) return
|
||||
super.visitVariable(declaration)
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn): IrExpression = if (expression.requiresAnyHandling()) {
|
||||
transformExpressionConsequently(expression)
|
||||
} else {
|
||||
super.visitReturn(expression)
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation) {
|
||||
if (result) return
|
||||
result = expression.arguments.any { it.type.needsHandling }
|
||||
if (result) return
|
||||
super.visitStringConcatenation(expression)
|
||||
}
|
||||
|
||||
override fun visitAnonymousInitializerNew(declaration: IrAnonymousInitializer): IrStatement = if (declaration.requiresAnyHandling()) {
|
||||
transformStatementConsequently(declaration)
|
||||
} else {
|
||||
super.visitAnonymousInitializerNew(declaration)
|
||||
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)
|
||||
}
|
||||
|
||||
private fun visitStatementContainer(container: IrStatementContainer) = if (container.statements.any { it.requiresAnyHandling() }) {
|
||||
multiFieldValueClassLowering.visitStatementContainer(container)
|
||||
inlineClassLowering.visitStatementContainer(container)
|
||||
} else {
|
||||
container.statements.replaceAll { it.transformStatement(this) }
|
||||
override fun visitExpression(expression: IrExpression) {
|
||||
if (result) return
|
||||
result = expression.type.needsHandling
|
||||
if (result) return
|
||||
super.visitExpression(expression)
|
||||
}
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
|
||||
visitStatementContainer(expression)
|
||||
return expression
|
||||
}
|
||||
|
||||
override fun visitBlockBody(body: IrBlockBody): IrBody {
|
||||
visitStatementContainer(body)
|
||||
return body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,8 +167,9 @@ class JvmBackendContext(
|
||||
|
||||
val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory, this)
|
||||
|
||||
val multiFieldValueClassReplacements =
|
||||
MemoizedMultiFieldValueClassReplacements(irFactory, this)
|
||||
val multiFieldValueClassReplacements = MemoizedMultiFieldValueClassReplacements(irFactory, this)
|
||||
|
||||
val valueClassLoweringDispatcherSharedData = MemoizedValueClassLoweringDispatcherSharedData()
|
||||
|
||||
val continuationClassesVarsCountByType: MutableMap<IrAttributeContainer, Map<Type, Int>> = hashMapOf()
|
||||
|
||||
|
||||
+3
-7
@@ -13,8 +13,11 @@ import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
||||
@@ -83,13 +86,6 @@ class MemoizedInlineClassReplacements(
|
||||
}
|
||||
}
|
||||
|
||||
override fun quickCheckIfFunctionIsNotApplicable(function: IrFunction) = !(
|
||||
function.parent.let { (it is IrClass && it.isSingleFieldValueClass) } ||
|
||||
function.dispatchReceiverParameter?.type?.isInlineClassType() == true ||
|
||||
function.extensionReceiverParameter?.type?.isInlineClassType() == true ||
|
||||
function.valueParameters.any { it.type.isInlineClassType() } || function.returnType.isInlineClassType()
|
||||
)
|
||||
|
||||
/**
|
||||
* Get the box function for an inline class. Concretely, this is a synthetic
|
||||
* static function named "box-impl" which takes an unboxed value and returns
|
||||
|
||||
+1
-11
@@ -22,10 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.IrComposite
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
||||
@@ -290,13 +287,6 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
}
|
||||
}
|
||||
|
||||
override fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean = !(
|
||||
function.parent.let { it is IrClass && it.isMultiFieldValueClass } ||
|
||||
function.dispatchReceiverParameter?.type?.needsMfvcFlattening() == true ||
|
||||
function.extensionReceiverParameter?.type?.needsMfvcFlattening() == true ||
|
||||
function.valueParameters.any { it.type.needsMfvcFlattening() }
|
||||
)
|
||||
|
||||
private val getReplacementForRegularClassConstructorImpl: (IrConstructor) -> IrConstructor? =
|
||||
storageManager.createMemoizedFunctionWithNullableValues { constructor ->
|
||||
when {
|
||||
|
||||
+1
-4
@@ -29,8 +29,7 @@ abstract class MemoizedValueClassAbstractReplacements(
|
||||
/**
|
||||
* Get a replacement for a function or a constructor.
|
||||
*/
|
||||
fun getReplacementFunction(function: IrFunction) =
|
||||
if (quickCheckIfFunctionIsNotApplicable(function)) null else getReplacementFunctionImpl(function)
|
||||
fun getReplacementFunction(function: IrFunction) = getReplacementFunctionImpl(function)
|
||||
|
||||
protected abstract val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction?
|
||||
|
||||
@@ -138,6 +137,4 @@ abstract class MemoizedValueClassAbstractReplacements(
|
||||
getReplacementFunction(function) ?: function.also {
|
||||
function.overriddenSymbols = replaceOverriddenSymbols(function)
|
||||
}
|
||||
|
||||
abstract fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// WITH_STDLIB
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// LANGUAGE: +ValueClasses
|
||||
// CHECK_BYTECODE_LISTING
|
||||
// FIR_IDENTICAL
|
||||
|
||||
@JvmInline
|
||||
value class Point(val x: Double, val y: Double)
|
||||
|
||||
|
||||
class A {
|
||||
fun b(p: Point) {
|
||||
res = p
|
||||
}
|
||||
}
|
||||
|
||||
var res: Any? = null
|
||||
|
||||
|
||||
fun toA(out: A): A {
|
||||
|
||||
fun g(p: List<Point>) {
|
||||
out.b(p.first())
|
||||
}
|
||||
|
||||
g(listOf(Point(1.0, 2.0)))
|
||||
return out
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = A()
|
||||
toA(a)
|
||||
require(res.toString() == Point(1.0, 2.0).toString())
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
@kotlin.Metadata
|
||||
public final class A {
|
||||
// source: 'nestedLoweringStart.kt'
|
||||
public method <init>(): void
|
||||
public final method b-1Nq-99U(p0: double, p1: double): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class NestedLoweringStartKt {
|
||||
// source: 'nestedLoweringStart.kt'
|
||||
private static @org.jetbrains.annotations.Nullable field res: java.lang.Object
|
||||
static method <clinit>(): void
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.Nullable method getRes(): java.lang.Object
|
||||
public final static method setRes(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
private final static method toA$g(p0: A, p1: java.util.List): void
|
||||
public final static @org.jetbrains.annotations.NotNull method toA(@org.jetbrains.annotations.NotNull p0: A): A
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmInline
|
||||
@kotlin.Metadata
|
||||
public final class Point {
|
||||
// source: 'nestedLoweringStart.kt'
|
||||
private final field x: double
|
||||
private final field y: double
|
||||
private synthetic method <init>(p0: double, p1: double): void
|
||||
public synthetic final static method box-impl(p0: double, p1: double): Point
|
||||
public final static method constructor-impl(p0: double, p1: double): void
|
||||
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
|
||||
public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
|
||||
public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
|
||||
public final method getX(): double
|
||||
public final method getY(): double
|
||||
public method hashCode(): int
|
||||
public static method hashCode-impl(p0: double, p1: double): int
|
||||
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
|
||||
public static method toString-impl(p0: double, p1: double): java.lang.String
|
||||
public synthetic final method unbox-impl-x(): double
|
||||
public synthetic final method unbox-impl-y(): double
|
||||
}
|
||||
+6
@@ -52149,6 +52149,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedLoweringStart.kt")
|
||||
public void testNestedLoweringStart() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/valueClasses/nestedLoweringStart.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nothingAsParameterType.kt")
|
||||
public void testNothingAsParameterType() throws Exception {
|
||||
|
||||
+6
@@ -52149,6 +52149,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
|
||||
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedLoweringStart.kt")
|
||||
public void testNestedLoweringStart() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/valueClasses/nestedLoweringStart.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nothingAsParameterType.kt")
|
||||
public void testNothingAsParameterType() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user