[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");
|
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
|
@Test
|
||||||
@TestMetadata("nothingAsParameterType.kt")
|
@TestMetadata("nothingAsParameterType.kt")
|
||||||
public void testNothingAsParameterType() throws Exception {
|
public void testNothingAsParameterType() throws Exception {
|
||||||
|
|||||||
+6
@@ -52149,6 +52149,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
|
|||||||
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
|
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
|
@Test
|
||||||
@TestMetadata("nothingAsParameterType.kt")
|
@TestMetadata("nothingAsParameterType.kt")
|
||||||
public void testNothingAsParameterType() throws Exception {
|
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.common.lower.irBlockBody
|
||||||
import org.jetbrains.kotlin.backend.jvm.*
|
import org.jetbrains.kotlin.backend.jvm.*
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
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.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.config.ApiVersion
|
import org.jetbrains.kotlin.config.ApiVersion
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
@@ -72,7 +71,6 @@ internal class JvmInlineClassLowering(
|
|||||||
|
|
||||||
override val specificMangle: SpecificMangle
|
override val specificMangle: SpecificMangle
|
||||||
get() = SpecificMangle.Inline
|
get() = SpecificMangle.Inline
|
||||||
override val IrType.needsHandling get() = isInlineClassType()
|
|
||||||
override fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration) = Unit
|
override fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration) = Unit
|
||||||
|
|
||||||
override fun visitClassNew(declaration: IrClass): IrClass {
|
override fun visitClassNew(declaration: IrClass): IrClass {
|
||||||
|
|||||||
-2
@@ -46,8 +46,6 @@ internal class JvmMultiFieldValueClassLowering(
|
|||||||
context: JvmBackendContext,
|
context: JvmBackendContext,
|
||||||
scopeStack: MutableList<ScopeWithIr>,
|
scopeStack: MutableList<ScopeWithIr>,
|
||||||
) : JvmValueClassAbstractLowering(context, scopeStack) {
|
) : JvmValueClassAbstractLowering(context, scopeStack) {
|
||||||
override val IrType.needsHandling: Boolean
|
|
||||||
get() = needsMfvcFlattening()
|
|
||||||
|
|
||||||
private sealed class MfvcNodeInstanceAccessor {
|
private sealed class MfvcNodeInstanceAccessor {
|
||||||
abstract val instance: MfvcNodeInstance
|
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.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.jvm.*
|
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.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
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.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.transformStatement
|
import org.jetbrains.kotlin.ir.transformStatement
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
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.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
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)
|
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)
|
internal abstract fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration)
|
||||||
|
|
||||||
// forbid other overrides without modifying dispatcher file JvmValueClassLoweringDispatcher.kt
|
// 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 visitErrorExpression(expression: IrErrorExpression) = super.visitErrorExpression(expression)
|
||||||
final override fun visitErrorCallExpression(expression: IrErrorCallExpression) = super.visitErrorCallExpression(expression)
|
final override fun visitErrorCallExpression(expression: IrErrorCallExpression) = super.visitErrorCallExpression(expression)
|
||||||
|
|
||||||
|
|
||||||
abstract val IrType.needsHandling: Boolean
|
|
||||||
}
|
}
|
||||||
|
|||||||
+145
-119
@@ -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.lower.loops.forLoopsPhase
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
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.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
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.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.transformStatement
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
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(
|
val jvmValueClassPhase = makeIrFilePhase(
|
||||||
::JvmValueClassLoweringDispatcher,
|
::JvmValueClassLoweringDispatcher,
|
||||||
@@ -32,7 +38,8 @@ val jvmValueClassPhase = makeIrFilePhase(
|
|||||||
prerequisite = setOf(forLoopsPhase, jvmBuiltInsPhase, collectionStubMethodLowering, singleAbstractMethodPhase),
|
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()
|
override val scopeStack: MutableList<ScopeWithIr> = mutableListOf()
|
||||||
private val inlineClassLowering: JvmInlineClassLowering = JvmInlineClassLowering(context, scopeStack)
|
private val inlineClassLowering: JvmInlineClassLowering = JvmInlineClassLowering(context, scopeStack)
|
||||||
private val multiFieldValueClassLowering: JvmMultiFieldValueClassLowering = JvmMultiFieldValueClassLowering(context, scopeStack)
|
private val multiFieldValueClassLowering: JvmMultiFieldValueClassLowering = JvmMultiFieldValueClassLowering(context, scopeStack)
|
||||||
@@ -42,158 +49,177 @@ internal class JvmValueClassLoweringDispatcher(context: JvmBackendContext) : IrE
|
|||||||
irFile.transformChildrenVoid()
|
irFile.transformChildrenVoid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitClassNew(declaration: IrClass): IrClass = if (declaration.requiresHandling()) {
|
||||||
private fun IrElement.requiresAnyHandling() =
|
|
||||||
requiresHandling(multiFieldValueClassLowering) || requiresHandling(inlineClassLowering)
|
|
||||||
|
|
||||||
override fun visitClassNew(declaration: IrClass): IrClass = if (declaration.requiresAnyHandling()) {
|
|
||||||
declaration
|
declaration
|
||||||
.let(multiFieldValueClassLowering::visitClassNew)
|
.let(multiFieldValueClassLowering::visitClassNew)
|
||||||
.let(inlineClassLowering::visitClassNew)
|
.let(inlineClassLowering::visitClassNew)
|
||||||
} else {
|
} else {
|
||||||
declaration.transformChildrenVoid()
|
|
||||||
for (innerDeclaration in declaration.declarations) {
|
|
||||||
multiFieldValueClassLowering.visitClassNewDeclarationsWhenParallel(innerDeclaration)
|
|
||||||
}
|
|
||||||
for (innerDeclaration in declaration.declarations) {
|
|
||||||
inlineClassLowering.visitClassNewDeclarationsWhenParallel(innerDeclaration)
|
|
||||||
}
|
|
||||||
declaration
|
declaration
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformExpressionConsequently(expression: IrExpression) = expression
|
private fun IrElement.requiresHandling(): Boolean {
|
||||||
.transform(multiFieldValueClassLowering, null)
|
val visitor = NeedsToVisit(context)
|
||||||
.transform(inlineClassLowering, null)
|
accept(visitor, null)
|
||||||
|
return visitor.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun transformStatementConsequently(statement: IrStatement) = statement
|
private class NeedsToVisit(private val context: JvmBackendContext) : IrElementVisitorVoid {
|
||||||
.transformStatement(multiFieldValueClassLowering)
|
var result = false
|
||||||
.transformStatement(inlineClassLowering)
|
private val replacements = context.valueClassLoweringDispatcherSharedData
|
||||||
|
private val visitedParameters = mutableSetOf<IrSymbol>()
|
||||||
|
|
||||||
private fun IrElement.requiresHandling(lowering: JvmValueClassAbstractLowering) =
|
override fun visitElement(element: IrElement) {
|
||||||
accept(object : IrElementVisitor<Boolean, Nothing?> {
|
if (!result) element.acceptChildrenVoid(this)
|
||||||
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 visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean =
|
private fun IrElement.acceptAndGetResult(): Boolean {
|
||||||
lowering.needsToVisitFunctionReference(expression) || super.visitFunctionReference(expression, data)
|
acceptVoid(this@NeedsToVisit)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: Nothing?): Boolean =
|
private val IrClass.needsHandling: Boolean
|
||||||
lowering.needsToVisitFunctionAccess(expression) || super.visitFunctionAccess(expression, data)
|
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 =
|
override fun visitClass(declaration: IrClass) {
|
||||||
lowering.needsToVisitCall(expression) || super.visitCall(expression, data)
|
visitClassHeader(declaration)
|
||||||
|
if (result) return
|
||||||
|
visitClassBody(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): Boolean =
|
private fun visitClassBody(declaration: IrClass) {
|
||||||
lowering.needsToVisitStringConcatenation(expression) || super.visitStringConcatenation(expression, data)
|
if (result) return
|
||||||
|
result = replacements.classResults.getOrPut(Body to declaration) {
|
||||||
|
declaration.declarations.any { it.acceptAndGetResult() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField, data: Nothing?): Boolean =
|
private fun visitClassHeader(declaration: IrClass) {
|
||||||
lowering.needsToVisitGetField(expression) || super.visitGetField(expression, data)
|
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 =
|
override fun visitFunction(declaration: IrFunction) = visitFunction(declaration, withBody = true)
|
||||||
lowering.needsToVisitSetField(expression) || super.visitSetField(expression, data)
|
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue, data: Nothing?): Boolean =
|
private fun visitFunctionHeader(declaration: IrFunction) {
|
||||||
lowering.needsToVisitGetValue(expression) || super.visitGetValue(expression, data)
|
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 =
|
private fun visitFunction(declaration: IrFunction, withBody: Boolean) {
|
||||||
lowering.needsToVisitSetValue(expression) || super.visitSetValue(expression, data)
|
visitFunctionHeader(declaration)
|
||||||
|
if (result) return
|
||||||
|
if(withBody) visitFunctionBody(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitVariable(declaration: IrVariable, data: Nothing?): Boolean =
|
private fun visitFunctionBody(declaration: IrFunction) {
|
||||||
lowering.needsToVisitVariable(declaration) || super.visitVariable(declaration, data)
|
if (result) return
|
||||||
|
result = replacements.functionResults.getOrPut(Body to declaration) {
|
||||||
|
declaration.body?.acceptAndGetResult() == true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean =
|
override fun visitValueParameter(declaration: IrValueParameter) {
|
||||||
lowering.needsToVisitReturn(expression) || super.visitReturn(expression, data)
|
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 =
|
override fun visitTypeParameter(declaration: IrTypeParameter) {
|
||||||
visitStatementContainer(expression)
|
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 =
|
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||||
visitStatementContainer(body)
|
if (result) return
|
||||||
|
visitFunction(expression.symbol.owner, withBody = false)
|
||||||
private fun visitStatementContainer(expression: IrStatementContainer) = expression.statements.any { it.accept(this, null) }
|
if (result) return
|
||||||
}, null)
|
|
||||||
|
|
||||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression = if (expression.requiresAnyHandling()) {
|
|
||||||
transformExpressionConsequently(expression)
|
|
||||||
} else {
|
|
||||||
super.visitFunctionReference(expression)
|
super.visitFunctionReference(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression = if (expression.requiresAnyHandling()) {
|
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
|
||||||
transformExpressionConsequently(expression)
|
if (result) return
|
||||||
} else {
|
visitFunction(expression.symbol.owner, withBody = false)
|
||||||
|
if (result) return
|
||||||
super.visitFunctionAccess(expression)
|
super.visitFunctionAccess(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression = if (expression.requiresAnyHandling()) {
|
override fun visitField(declaration: IrField) = visitField(declaration, withBody = true)
|
||||||
transformExpressionConsequently(expression)
|
|
||||||
} else {
|
private fun visitFieldHeader(declaration: IrField) {
|
||||||
super.visitCall(expression)
|
if (result) return
|
||||||
|
result = replacements.fieldResults.getOrPut(Header to declaration) {
|
||||||
|
declaration.type.needsHandling
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression = if (expression.requiresAnyHandling()) {
|
private fun visitFieldBody(declaration: IrField) {
|
||||||
transformExpressionConsequently(expression)
|
if (result) return
|
||||||
} else {
|
result = replacements.fieldResults.getOrPut(Body to declaration) {
|
||||||
super.visitStringConcatenation(expression)
|
super.visitField(declaration)
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField): IrExpression = if (expression.requiresAnyHandling()) {
|
private fun visitField(declaration: IrField, withBody: Boolean) {
|
||||||
transformExpressionConsequently(expression)
|
visitFieldHeader(declaration)
|
||||||
} else {
|
if (withBody) visitFieldBody(declaration)
|
||||||
super.visitGetField(expression)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSetField(expression: IrSetField): IrExpression = if (expression.requiresAnyHandling()) {
|
override fun visitFieldAccess(expression: IrFieldAccessExpression) {
|
||||||
transformExpressionConsequently(expression)
|
if (result) return
|
||||||
} else {
|
visitField(expression.symbol.owner, withBody = false)
|
||||||
super.visitSetField(expression)
|
if (result) return
|
||||||
|
super.visitFieldAccess(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression = if (expression.requiresAnyHandling()) {
|
override fun visitVariable(declaration: IrVariable) {
|
||||||
transformExpressionConsequently(expression)
|
if (result) return
|
||||||
} else {
|
result = declaration.type.needsHandling
|
||||||
super.visitGetValue(expression)
|
if (result) return
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
super.visitVariable(declaration)
|
super.visitVariable(declaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn): IrExpression = if (expression.requiresAnyHandling()) {
|
|
||||||
transformExpressionConsequently(expression)
|
override fun visitStringConcatenation(expression: IrStringConcatenation) {
|
||||||
} else {
|
if (result) return
|
||||||
super.visitReturn(expression)
|
result = expression.arguments.any { it.type.needsHandling }
|
||||||
|
if (result) return
|
||||||
|
super.visitStringConcatenation(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitAnonymousInitializerNew(declaration: IrAnonymousInitializer): IrStatement = if (declaration.requiresAnyHandling()) {
|
override fun visitCall(expression: IrCall) {
|
||||||
transformStatementConsequently(declaration)
|
if (result) return
|
||||||
} else {
|
if (expression.symbol == context.irBuiltIns.eqeqSymbol) {
|
||||||
super.visitAnonymousInitializerNew(declaration)
|
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() }) {
|
override fun visitExpression(expression: IrExpression) {
|
||||||
multiFieldValueClassLowering.visitStatementContainer(container)
|
if (result) return
|
||||||
inlineClassLowering.visitStatementContainer(container)
|
result = expression.type.needsHandling
|
||||||
} else {
|
if (result) return
|
||||||
container.statements.replaceAll { it.transformStatement(this) }
|
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 inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory, this)
|
||||||
|
|
||||||
val multiFieldValueClassReplacements =
|
val multiFieldValueClassReplacements = MemoizedMultiFieldValueClassReplacements(irFactory, this)
|
||||||
MemoizedMultiFieldValueClassReplacements(irFactory, this)
|
|
||||||
|
val valueClassLoweringDispatcherSharedData = MemoizedValueClassLoweringDispatcherSharedData()
|
||||||
|
|
||||||
val continuationClassesVarsCountByType: MutableMap<IrAttributeContainer, Map<Type, Int>> = hashMapOf()
|
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.addValueParameter
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.IrSimpleTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
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.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
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
|
* 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
|
* 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.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
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.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
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? =
|
private val getReplacementForRegularClassConstructorImpl: (IrConstructor) -> IrConstructor? =
|
||||||
storageManager.createMemoizedFunctionWithNullableValues { constructor ->
|
storageManager.createMemoizedFunctionWithNullableValues { constructor ->
|
||||||
when {
|
when {
|
||||||
|
|||||||
+1
-4
@@ -29,8 +29,7 @@ abstract class MemoizedValueClassAbstractReplacements(
|
|||||||
/**
|
/**
|
||||||
* Get a replacement for a function or a constructor.
|
* Get a replacement for a function or a constructor.
|
||||||
*/
|
*/
|
||||||
fun getReplacementFunction(function: IrFunction) =
|
fun getReplacementFunction(function: IrFunction) = getReplacementFunctionImpl(function)
|
||||||
if (quickCheckIfFunctionIsNotApplicable(function)) null else getReplacementFunctionImpl(function)
|
|
||||||
|
|
||||||
protected abstract val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction?
|
protected abstract val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction?
|
||||||
|
|
||||||
@@ -138,6 +137,4 @@ abstract class MemoizedValueClassAbstractReplacements(
|
|||||||
getReplacementFunction(function) ?: function.also {
|
getReplacementFunction(function) ?: function.also {
|
||||||
function.overriddenSymbols = replaceOverriddenSymbols(function)
|
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");
|
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
|
@Test
|
||||||
@TestMetadata("nothingAsParameterType.kt")
|
@TestMetadata("nothingAsParameterType.kt")
|
||||||
public void testNothingAsParameterType() throws Exception {
|
public void testNothingAsParameterType() throws Exception {
|
||||||
|
|||||||
+6
@@ -52149,6 +52149,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
|
|||||||
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
|
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
|
@Test
|
||||||
@TestMetadata("nothingAsParameterType.kt")
|
@TestMetadata("nothingAsParameterType.kt")
|
||||||
public void testNothingAsParameterType() throws Exception {
|
public void testNothingAsParameterType() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user