[IR] Implement bridges generation for MFVC
#KT-1179
This commit is contained in:
committed by
teamcity
parent
2896f5613d
commit
ee2d327243
+60
-12
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import kotlin.collections.set
|
||||
|
||||
/*
|
||||
* Generate bridge methods to fix virtual dispatch after type erasure and to adapt Kotlin collections to
|
||||
@@ -341,12 +342,14 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
for (override in irFunction.allOverridden()) {
|
||||
if (override.isFakeOverride) continue
|
||||
|
||||
val signature = override.jvmMethod
|
||||
val target = override.mangleFunctionIfNeeded()
|
||||
|
||||
val signature = target.jvmMethod
|
||||
if (targetMethod != signature && signature !in blacklist) {
|
||||
val bridge = generated.getOrPut(signature) {
|
||||
Bridge(override, signature)
|
||||
Bridge(target, signature)
|
||||
}
|
||||
bridge.overriddenSymbols += override.symbol
|
||||
bridge.overriddenSymbols += target.symbol
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,6 +361,18 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
.forEach { irClass.addBridge(it, bridgeTarget) }
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.mangleFunctionIfNeeded(): IrSimpleFunction {
|
||||
if (!hasMangledReturnType && !hasMangledParameters()) return this
|
||||
val replacement = context.multiFieldValueClassReplacements.getReplacementFunction(this)
|
||||
?: context.inlineClassReplacements.getReplacementFunction(this)
|
||||
?: return this
|
||||
if (name.asString().substringAfterLast('-') == replacement.name.asString().substringAfterLast('-')) {
|
||||
// function is already mangled
|
||||
return this
|
||||
}
|
||||
return replacement
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.isClashingWithPotentialBridge(name: Name, signature: Method): Boolean =
|
||||
(!this.isFakeOverride || this.modality == Modality.FINAL) && this.name == name && this.jvmMethod == signature
|
||||
|
||||
@@ -612,16 +627,49 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
) =
|
||||
irCastIfNeeded(
|
||||
irCall(target, origin = IrStatementOrigin.BRIDGE_DELEGATION, superQualifierSymbol = superQualifierSymbol).apply {
|
||||
for ((param, targetParam) in bridge.explicitParameters.zip(target.explicitParameters)) {
|
||||
putArgument(
|
||||
targetParam,
|
||||
irGet(param).let { argument ->
|
||||
if (param == bridge.dispatchReceiverParameter)
|
||||
argument
|
||||
else
|
||||
irCastIfNeeded(argument, targetParam.type.upperBound)
|
||||
val mfvcOrOriginal =
|
||||
this@BridgeLowering.context.inlineClassReplacements.originalFunctionForMethodReplacement[target] ?: target
|
||||
val structure = with(this@BridgeLowering.context.multiFieldValueClassReplacements) {
|
||||
originalFunctionForMethodReplacement[mfvcOrOriginal]
|
||||
?.let { bindingParameterTemplateStructure[it] }
|
||||
?.also { structure ->
|
||||
val errorMessage = { "Bad parameters structure: $structure" }
|
||||
require(structure.size == bridge.explicitParametersCount) { errorMessage() }
|
||||
require(structure.sumOf { it.valueParameters.size } == target.explicitParametersCount) { errorMessage() }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun irGetOrCast(bridgeParameter: IrValueParameter, targetParameter: IrValueParameter) =
|
||||
irGet(bridgeParameter).let { argument ->
|
||||
if (bridgeParameter == bridge.dispatchReceiverParameter)
|
||||
argument
|
||||
else
|
||||
irCastIfNeeded(argument, targetParameter.type.upperBound)
|
||||
}
|
||||
|
||||
val targetParameters = target.explicitParameters
|
||||
val flattenedBridgeArguments = when (structure) {
|
||||
null -> bridge.explicitParameters.zip(target.explicitParameters, ::irGetOrCast)
|
||||
else -> {
|
||||
var index = 0
|
||||
(structure zip bridge.explicitParameters).flatMap { (remappedParameter, bridgeParameter) ->
|
||||
when (remappedParameter) {
|
||||
is MultiFieldValueClassMapping -> remappedParameter.declarations.unboxMethods.map { unboxFunction ->
|
||||
irCall(unboxFunction).apply {
|
||||
dispatchReceiver =
|
||||
irCastIfNeeded(irGet(bridgeParameter), remappedParameter.declarations.valueClass.defaultType)
|
||||
}
|
||||
}.also { index += it.size }
|
||||
is RegularMapping -> listOf(irGetOrCast(bridgeParameter, targetParameters[index++]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
require(targetParameters.size == flattenedBridgeArguments.size) {
|
||||
"Incorrect number of arguments: ${flattenedBridgeArguments.size} instead of ${targetParameters.size}"
|
||||
}
|
||||
for ((targetParam, argument) in target.explicitParameters zip flattenedBridgeArguments) {
|
||||
putArgument(targetParam, argument)
|
||||
}
|
||||
},
|
||||
bridge.returnType.upperBound
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ private class JvmDefaultConstructorLowering(val context: JvmBackendContext) : Cl
|
||||
if (DescriptorVisibilities.isPrivate(primaryConstructor.visibility))
|
||||
return
|
||||
|
||||
if (primaryConstructor.hasMangledParameters)
|
||||
if (primaryConstructor.hasMangledParameters())
|
||||
return
|
||||
|
||||
if (primaryConstructor.valueParameters.isEmpty() || !primaryConstructor.valueParameters.all { it.hasDefaultValue() })
|
||||
|
||||
+1
-61
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
@@ -30,8 +29,6 @@ import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
|
||||
|
||||
val jvmInlineClassPhase = makeIrFilePhase(
|
||||
@@ -117,64 +114,7 @@ private class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClass
|
||||
)
|
||||
}
|
||||
|
||||
override fun createBridgeFunction(
|
||||
function: IrSimpleFunction,
|
||||
replacement: IrSimpleFunction
|
||||
): IrSimpleFunction {
|
||||
val bridgeFunction = createBridgeDeclaration(
|
||||
function,
|
||||
when {
|
||||
// If the original function has signature which need mangling we still need to replace it with a mangled version.
|
||||
(!function.isFakeOverride || function.findInterfaceImplementation(context.state.jvmDefaultMode) != null) &&
|
||||
function.signatureRequiresMangling() ->
|
||||
replacement.name
|
||||
// Since we remove the corresponding property symbol from the bridge we need to resolve getter/setter
|
||||
// names at this point.
|
||||
replacement.isGetter ->
|
||||
Name.identifier(JvmAbi.getterName(replacement.correspondingPropertySymbol!!.owner.name.asString()))
|
||||
replacement.isSetter ->
|
||||
Name.identifier(JvmAbi.setterName(replacement.correspondingPropertySymbol!!.owner.name.asString()))
|
||||
else ->
|
||||
function.name
|
||||
}
|
||||
)
|
||||
|
||||
// Update the overridden symbols to point to their inline class replacements
|
||||
bridgeFunction.overriddenSymbols = replacement.overriddenSymbols
|
||||
|
||||
// Replace the function body with a wrapper
|
||||
if (bridgeFunction.isFakeOverride && bridgeFunction.parentAsClass.isSingleFieldValueClass) {
|
||||
// Fake overrides redirect from the replacement to the original function, which is in turn replaced during interfacePhase.
|
||||
createBridgeBody(replacement, bridgeFunction)
|
||||
} else {
|
||||
createBridgeBody(bridgeFunction, replacement)
|
||||
}
|
||||
return bridgeFunction
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.signatureRequiresMangling() =
|
||||
fullValueParameterList.any { it.type.requiresMangling } ||
|
||||
context.state.functionsWithInlineClassReturnTypesMangled && returnType.requiresMangling
|
||||
|
||||
// We may need to add a bridge method for inline class methods with static replacements. Ideally, we'd do this in BridgeLowering,
|
||||
// but unfortunately this is a special case in the old backend. The bridge method is not marked as such and does not follow the normal
|
||||
// visibility rules for bridge methods.
|
||||
private fun createBridgeDeclaration(source: IrSimpleFunction, mangledName: Name) =
|
||||
context.irFactory.buildFun {
|
||||
updateFrom(source)
|
||||
name = mangledName
|
||||
returnType = source.returnType
|
||||
}.apply {
|
||||
copyParameterDeclarationsFrom(source)
|
||||
annotations = source.annotations
|
||||
parent = source.parent
|
||||
// We need to ensure that this bridge has the same attribute owner as its static inline class replacement, since this
|
||||
// is used in [CoroutineCodegen.isStaticInlineClassReplacementDelegatingCall] to identify the bridge and avoid generating
|
||||
// a continuation class.
|
||||
copyAttributes(source)
|
||||
}
|
||||
|
||||
private fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction) {
|
||||
override fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction, original: IrFunction, inverted: Boolean) {
|
||||
source.body = context.createIrBuilder(source.symbol, source.startOffset, source.endOffset).run {
|
||||
irExprBody(irCall(target).apply {
|
||||
passTypeArgumentsFrom(source)
|
||||
|
||||
+58
-17
@@ -9,7 +9,12 @@ import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
|
||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
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.*
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.MultiFieldValueClassMapping
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.RegularMapping
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.ValueParameterTemplate
|
||||
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassSpecificDeclarations.ImplementationAgnostic
|
||||
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassSpecificDeclarations.VirtualProperty
|
||||
@@ -55,8 +60,12 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
symbol2setters[original] = listOf(if (replacement.isAssignable) { _, value -> irSet(replacement, value) } else null)
|
||||
}
|
||||
|
||||
fun remapSymbol(original: IrValueSymbol, unboxed: List<VirtualProperty<Unit>>): Unit =
|
||||
remapSymbol(original, replacements.getDeclarations(original.owner.type.erasedUpperBound)!!.ImplementationAgnostic(unboxed))
|
||||
fun remapSymbol(
|
||||
original: IrValueSymbol,
|
||||
unboxed: List<VirtualProperty<Unit>>,
|
||||
declarations: MultiFieldValueClassSpecificDeclarations
|
||||
): Unit =
|
||||
remapSymbol(original, declarations.ImplementationAgnostic(unboxed))
|
||||
|
||||
fun remapSymbol(original: IrValueSymbol, unboxed: ImplementationAgnostic<Unit>) {
|
||||
symbol2getter[original] = {
|
||||
@@ -314,9 +323,39 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
valueClass.declarations += properties.values.map { it.getter!!.apply { parent = valueClass } }
|
||||
}
|
||||
|
||||
override fun createBridgeFunction(function: IrSimpleFunction, replacement: IrSimpleFunction): IrSimpleFunction? {
|
||||
return null // todo
|
||||
// todo change return type to non-nullable for base class
|
||||
override fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction, original: IrFunction, inverted: Boolean) {
|
||||
|
||||
allScopes.push(createScope(source))
|
||||
source.body = context.createIrBuilder(source.symbol, source.startOffset, source.endOffset).run {
|
||||
if (inverted) {
|
||||
irExprBody(irCall(target).apply {
|
||||
passTypeArgumentsFrom(source)
|
||||
val structure: List<RemappedParameter> = replacements.bindingParameterTemplateStructure[original]!!
|
||||
var flattenedIndex = 0
|
||||
for ((remappedParameter, targetParameter) in structure zip target.explicitParameters) {
|
||||
when (remappedParameter) {
|
||||
is MultiFieldValueClassMapping -> putArgument(
|
||||
targetParameter,
|
||||
irCall(remappedParameter.declarations.boxMethod).apply {
|
||||
source.explicitParameters
|
||||
.slice(flattenedIndex until flattenedIndex + remappedParameter.valueParameters.size)
|
||||
.forEachIndexed { index, boxParameter -> putValueArgument(index, irGet(boxParameter)) }
|
||||
.also { flattenedIndex += remappedParameter.valueParameters.size }
|
||||
})
|
||||
is RegularMapping -> putArgument(targetParameter, irGet(source.explicitParameters[flattenedIndex++]))
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
irExprBody(irCall(original).apply { // not target as it will be replaced during lowering
|
||||
passTypeArgumentsFrom(source)
|
||||
for ((parameter, newParameter) in source.explicitParameters.zip(original.explicitParameters)) {
|
||||
putArgument(newParameter, irGet(parameter))
|
||||
}
|
||||
}).transform(this@JvmMultiFieldValueClassLowering, null)
|
||||
}
|
||||
}
|
||||
allScopes.pop()
|
||||
}
|
||||
|
||||
override fun addBindingsFor(original: IrFunction, replacement: IrFunction) {
|
||||
@@ -324,19 +363,19 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
require(parametersStructure.size == original.explicitParameters.size) {
|
||||
"Wrong value parameters structure: $parametersStructure"
|
||||
}
|
||||
require(parametersStructure.sumOf { it.size } == replacement.explicitParameters.size) {
|
||||
require(parametersStructure.sumOf { it.valueParameters.size } == replacement.explicitParameters.size) {
|
||||
"Wrong value parameters structure: $parametersStructure"
|
||||
}
|
||||
val old2newList = original.explicitParameters.zip(
|
||||
parametersStructure.scan(0) { partial: Int, templates: List<ValueParameterTemplate> -> partial + templates.size }
|
||||
parametersStructure.scan(0) { partial: Int, templates: RemappedParameter -> partial + templates.valueParameters.size }
|
||||
.zipWithNext { start: Int, finish: Int -> replacement.explicitParameters.slice(start until finish) }
|
||||
)
|
||||
for ((param, newParamList) in old2newList) {
|
||||
val single = newParamList.singleOrNull()
|
||||
if (single != null) {
|
||||
valueDeclarationsRemapper.remapSymbol(param.symbol, single)
|
||||
} else {
|
||||
valueDeclarationsRemapper.remapSymbol(param.symbol, newParamList.map { VirtualProperty(it) })
|
||||
for (i in old2newList.indices) {
|
||||
val (param, newParamList) = old2newList[i]
|
||||
when (val structure = parametersStructure[i]) {
|
||||
is MultiFieldValueClassMapping ->
|
||||
valueDeclarationsRemapper.remapSymbol(param.symbol, newParamList.map { VirtualProperty(it) }, structure.declarations)
|
||||
is RegularMapping -> valueDeclarationsRemapper.remapSymbol(param.symbol, newParamList.single())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,7 +391,8 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
val initializersStatements = valueClass.declarations.filterIsInstance<IrAnonymousInitializer>().flatMap { it.body.statements }
|
||||
valueDeclarationsRemapper.remapSymbol(
|
||||
oldPrimaryConstructor.constructedClass.thisReceiver!!.symbol,
|
||||
primaryConstructorImpl.valueParameters.map { VirtualProperty(it) }
|
||||
primaryConstructorImpl.valueParameters.map { VirtualProperty(it) },
|
||||
this,
|
||||
)
|
||||
primaryConstructorImpl.body = context.createIrBuilder(primaryConstructorImpl.symbol).irBlockBody {
|
||||
for (stmt in initializersStatements) {
|
||||
@@ -472,8 +512,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
val parameter2expression = typedArgumentList(originalFunction, original)
|
||||
val structure = replacements.bindingParameterTemplateStructure[originalFunction]!!
|
||||
require(parameter2expression.size == structure.size)
|
||||
require(structure.sumOf { it.size } == replacement.explicitParametersCount)
|
||||
val newArguments: List<IrExpression?> = makeNewArguments(parameter2expression.map { (_, argument) -> argument }, structure)
|
||||
require(structure.sumOf { it.valueParameters.size } == replacement.explicitParametersCount)
|
||||
val newArguments: List<IrExpression?> =
|
||||
makeNewArguments(parameter2expression.map { (_, argument) -> argument }, structure.map { it.valueParameters })
|
||||
+irCall(replacement.symbol).apply {
|
||||
copyTypeArgumentsFrom(original)
|
||||
for ((parameter, argument) in replacement.explicitParameters zip newArguments) {
|
||||
@@ -586,7 +627,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
initializer?.let {
|
||||
flattenExpressionTo(it, variables.toGettersAndSetters())
|
||||
}
|
||||
valueDeclarationsRemapper.remapSymbol(declaration.symbol, variables.map { VirtualProperty(it) })
|
||||
valueDeclarationsRemapper.remapSymbol(declaration.symbol, variables.map { VirtualProperty(it) }, declarations)
|
||||
}
|
||||
}
|
||||
return super.visitVariable(declaration)
|
||||
|
||||
+2
-2
@@ -10,10 +10,10 @@ import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.getRequiresMangling
|
||||
import org.jetbrains.kotlin.backend.jvm.hasMangledReturnType
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.eraseTypeParameters
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.needsAccessor
|
||||
import org.jetbrains.kotlin.backend.jvm.requiresMangling
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
@@ -222,7 +222,7 @@ class JvmPropertiesLowering(private val backendContext: JvmBackendContext) : IrE
|
||||
val getter = property.getter
|
||||
if (getter != null) {
|
||||
val needsMangling =
|
||||
getter.extensionReceiverParameter?.type?.requiresMangling == true ||
|
||||
getter.extensionReceiverParameter?.type?.getRequiresMangling(includeInline = true, includeMFVC = false) == true ||
|
||||
(state.functionsWithInlineClassReturnTypesMangled && getter.hasMangledReturnType)
|
||||
val mangled = if (needsMangling) inlineClassReplacements.getReplacementFunction(getter) else null
|
||||
defaultMethodSignatureMapper.mapFunctionName(mangled ?: getter)
|
||||
|
||||
+68
-9
@@ -7,21 +7,21 @@ 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.ir.copyParameterDeclarationsFrom
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.pop
|
||||
import org.jetbrains.kotlin.backend.common.push
|
||||
import org.jetbrains.kotlin.backend.jvm.InlineClassAbi
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedValueClassAbstractReplacements
|
||||
import org.jetbrains.kotlin.backend.jvm.*
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.transformStatement
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendContext) : FileLoweringPass,
|
||||
@@ -121,7 +121,7 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
|
||||
|
||||
val bridgeFunction = createBridgeFunction(function, replacement)
|
||||
|
||||
return listOfNotNull(replacement, bridgeFunction)
|
||||
return listOf(replacement, bridgeFunction)
|
||||
}
|
||||
|
||||
final override fun visitReturn(expression: IrReturn): IrExpression {
|
||||
@@ -166,10 +166,69 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
|
||||
super.visitAnonymousInitializerNew(declaration)
|
||||
|
||||
protected abstract fun addBindingsFor(original: IrFunction, replacement: IrFunction)
|
||||
protected abstract fun createBridgeFunction(function: IrSimpleFunction, replacement: IrSimpleFunction): IrSimpleFunction?
|
||||
|
||||
private fun createBridgeFunction(
|
||||
function: IrSimpleFunction,
|
||||
replacement: IrSimpleFunction
|
||||
): IrSimpleFunction {
|
||||
val bridgeFunction = createBridgeDeclaration(
|
||||
function,
|
||||
when {
|
||||
// If the original function has signature which need mangling we still need to replace it with a mangled version.
|
||||
(!function.isFakeOverride || function.findInterfaceImplementation(context.state.jvmDefaultMode) != null) &&
|
||||
function.signatureRequiresMangling() ->
|
||||
replacement.name
|
||||
// Since we remove the corresponding property symbol from the bridge we need to resolve getter/setter
|
||||
// names at this point.
|
||||
replacement.isGetter ->
|
||||
Name.identifier(JvmAbi.getterName(replacement.correspondingPropertySymbol!!.owner.name.asString()))
|
||||
replacement.isSetter ->
|
||||
Name.identifier(JvmAbi.setterName(replacement.correspondingPropertySymbol!!.owner.name.asString()))
|
||||
else ->
|
||||
function.name
|
||||
}
|
||||
)
|
||||
|
||||
// Update the overridden symbols to point to their inline class replacements
|
||||
bridgeFunction.overriddenSymbols = replacement.overriddenSymbols
|
||||
|
||||
// Replace the function body with a wrapper
|
||||
if (bridgeFunction.isFakeOverride && bridgeFunction.parentAsClass.isSpecificLoweringLogicApplicable()) {
|
||||
// Fake overrides redirect from the replacement to the original function, which is in turn replaced during interfacePhase.
|
||||
createBridgeBody(replacement, bridgeFunction, function, true)
|
||||
} else {
|
||||
createBridgeBody(bridgeFunction, replacement, function, false)
|
||||
}
|
||||
return bridgeFunction
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.signatureRequiresMangling() =
|
||||
fullValueParameterList.any { it.type.getRequiresMangling() } ||
|
||||
context.state.functionsWithInlineClassReturnTypesMangled && returnType.getRequiresMangling() && returnType.isInlineClassType()
|
||||
|
||||
protected fun typedArgumentList(function: IrFunction, expression: IrMemberAccessExpression<*>) = listOfNotNull(
|
||||
function.dispatchReceiverParameter?.let { it to expression.dispatchReceiver },
|
||||
function.extensionReceiverParameter?.let { it to expression.extensionReceiver }
|
||||
) + function.valueParameters.map { it to expression.getValueArgument(it.index) }
|
||||
|
||||
|
||||
// We may need to add a bridge method for inline class methods with static replacements. Ideally, we'd do this in BridgeLowering,
|
||||
// but unfortunately this is a special case in the old backend. The bridge method is not marked as such and does not follow the normal
|
||||
// visibility rules for bridge methods.
|
||||
private fun createBridgeDeclaration(source: IrSimpleFunction, mangledName: Name) =
|
||||
context.irFactory.buildFun {
|
||||
updateFrom(source)
|
||||
name = mangledName
|
||||
returnType = source.returnType
|
||||
}.apply {
|
||||
copyParameterDeclarationsFrom(source)
|
||||
annotations = source.annotations
|
||||
parent = source.parent
|
||||
// We need to ensure that this bridge has the same attribute owner as its static inline class replacement, since this
|
||||
// is used in [CoroutineCodegen.isStaticInlineClassReplacementDelegatingCall] to identify the bridge and avoid generating
|
||||
// a continuation class.
|
||||
copyAttributes(source)
|
||||
}
|
||||
|
||||
protected abstract fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction, original: IrFunction, inverted: Boolean)
|
||||
}
|
||||
+1
-1
@@ -370,7 +370,7 @@ private class SyntheticAccessorTransformer(
|
||||
|
||||
val constructedClass = constructedClass
|
||||
|
||||
if (!DescriptorVisibilities.isPrivate(visibility) && !constructedClass.isSingleFieldValueClass && hasMangledParameters &&
|
||||
if (!DescriptorVisibilities.isPrivate(visibility) && !constructedClass.isValue && hasMangledParameters() &&
|
||||
!constructedClass.isAnonymousObject
|
||||
) return true
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ object InlineClassAbi {
|
||||
): String? =
|
||||
collectFunctionSignatureForManglingSuffix(
|
||||
useOldMangleRules,
|
||||
valueParameters.any { it.requiresMangling },
|
||||
valueParameters.any { it.getRequiresMangling() },
|
||||
// The JVM backend computes mangled names after creating suspend function views, but before default argument
|
||||
// stub insertion. It would be nice if this part of the continuation lowering happened earlier in the pipeline.
|
||||
// TODO: Move suspend function view creation before JvmInlineClassLowering.
|
||||
@@ -124,19 +124,28 @@ object InlineClassAbi {
|
||||
get() = (this as IrSimpleFunction).correspondingPropertySymbol!!.owner.name
|
||||
}
|
||||
|
||||
val IrType.requiresMangling: Boolean
|
||||
get() {
|
||||
val irClass = erasedUpperBound
|
||||
return irClass.isValue && irClass.fqNameWhenAvailable != StandardNames.RESULT_FQ_NAME
|
||||
fun IrType.getRequiresMangling(includeInline: Boolean = true, includeMFVC: Boolean = true): Boolean {
|
||||
val irClass = erasedUpperBound
|
||||
return irClass.fqNameWhenAvailable != StandardNames.RESULT_FQ_NAME && when {
|
||||
irClass.isSingleFieldValueClass -> includeInline
|
||||
irClass.isMultiFieldValueClass -> includeMFVC
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
val IrFunction.fullValueParameterList: List<IrValueParameter>
|
||||
get() = listOfNotNull(extensionReceiverParameter) + valueParameters
|
||||
|
||||
val IrFunction.hasMangledParameters: Boolean
|
||||
get() = dispatchReceiverParameter != null && parentAsClass.isValue ||
|
||||
fullValueParameterList.any { it.type.requiresMangling } ||
|
||||
(this is IrConstructor && constructedClass.isValue)
|
||||
fun IrFunction.hasMangledParameters(includeInline: Boolean = true, includeMFVC: Boolean = true): Boolean =
|
||||
(dispatchReceiverParameter != null && when {
|
||||
parentAsClass.isSingleFieldValueClass -> includeInline
|
||||
parentAsClass.isMultiFieldValueClass -> includeMFVC
|
||||
else -> false
|
||||
}) || fullValueParameterList.any { it.type.getRequiresMangling(includeInline, includeMFVC) } || (this is IrConstructor && when {
|
||||
constructedClass.isSingleFieldValueClass -> includeInline
|
||||
constructedClass.isMultiFieldValueClass -> includeMFVC
|
||||
else -> false
|
||||
})
|
||||
|
||||
val IrFunction.hasMangledReturnType: Boolean
|
||||
get() = returnType.isInlineClassType() && parentClassOrNull?.isFileClass != true
|
||||
|
||||
+3
-2
@@ -40,7 +40,7 @@ class MemoizedInlineClassReplacements(
|
||||
private val storageManager = LockBasedStorageManager("inline-class-replacements")
|
||||
|
||||
val originalFunctionForStaticReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
|
||||
internal val originalFunctionForMethodReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
|
||||
val originalFunctionForMethodReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
|
||||
|
||||
/**
|
||||
* Get a replacement for a function or a constructor.
|
||||
@@ -76,7 +76,8 @@ class MemoizedInlineClassReplacements(
|
||||
}
|
||||
|
||||
// Otherwise, mangle functions with mangled parameters, ignoring constructors
|
||||
it is IrSimpleFunction && !it.isFromJava() && (it.hasMangledParameters || mangleReturnTypes && it.hasMangledReturnType) ->
|
||||
it is IrSimpleFunction && !it.isFromJava() &&
|
||||
(it.hasMangledParameters(includeMFVC = false) || mangleReturnTypes && it.hasMangledReturnType) ->
|
||||
createMethodReplacement(it)
|
||||
|
||||
else ->
|
||||
|
||||
+33
-16
@@ -35,9 +35,9 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
) : MemoizedValueClassAbstractReplacements(irFactory, context) {
|
||||
private val storageManager = LockBasedStorageManager("multi-field-value-class-replacements")
|
||||
|
||||
internal val originalFunctionForStaticReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
|
||||
internal val originalFunctionForMethodReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
|
||||
internal val originalConstructorForConstructorReplacement: MutableMap<IrConstructor, IrConstructor> = ConcurrentHashMap()
|
||||
val originalFunctionForStaticReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
|
||||
val originalFunctionForMethodReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
|
||||
private val originalConstructorForConstructorReplacement: MutableMap<IrConstructor, IrConstructor> = ConcurrentHashMap()
|
||||
|
||||
val getDeclarations: (IrClass) -> MultiFieldValueClassSpecificDeclarations? =
|
||||
storageManager.createMemoizedFunctionWithNullableValues {
|
||||
@@ -77,24 +77,24 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.makeValueParametersFromTemplate(newFlattenedParameters: List<List<ValueParameterTemplate>>) =
|
||||
newFlattenedParameters.flatten().mapIndexed { index: Int, template -> template.toParameter(this, index) }
|
||||
private fun IrFunction.makeValueParametersFromTemplate(newFlattenedParameters: List<RemappedParameter>) = newFlattenedParameters
|
||||
.flatMap { it.valueParameters }.mapIndexed { index: Int, template -> template.toParameter(this, index) }
|
||||
|
||||
private fun List<ValueParameterTemplate>.grouped(
|
||||
originWhenFlattenedAndNotSpecified: IrDeclarationOrigin? = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER
|
||||
): List<List<ValueParameterTemplate>> = map { parameter ->
|
||||
val declaration = parameter.type.takeIf { !it.isNullable() }?.getClass()?.let { getDeclarations(it) }
|
||||
?: return@map listOf(parameter)
|
||||
): List<RemappedParameter> = map { parameter ->
|
||||
val declarations = parameter.type.takeIf { !it.isNullable() }?.getClass()?.let { getDeclarations(it) }
|
||||
?: return@map RemappedParameter.RegularMapping(parameter)
|
||||
require(!parameter.original.hasDefaultValue()) { "Default parameters values are not supported for multi-field value classes" }
|
||||
declaration.leaves.map { leaf ->
|
||||
RemappedParameter.MultiFieldValueClassMapping(declarations, declarations.leaves.map { leaf ->
|
||||
ValueParameterTemplate(
|
||||
name = "${parameter.name}$${declaration.nodeFullNames[leaf]!!}",
|
||||
name = "${parameter.name}$${declarations.nodeFullNames[leaf]!!}",
|
||||
type = leaf.type,
|
||||
origin = parameter.origin ?: originWhenFlattenedAndNotSpecified,
|
||||
defaultValue = null,
|
||||
original = parameter.original,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun buildReplacement(
|
||||
@@ -115,8 +115,8 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
|
||||
private fun makeGroupedValueParametersFrom(
|
||||
function: IrFunction, includeDispatcherReceiver: Boolean
|
||||
): List<List<ValueParameterTemplate>> {
|
||||
val newFlattenedParameters = mutableListOf<List<ValueParameterTemplate>>()
|
||||
): List<RemappedParameter> {
|
||||
val newFlattenedParameters = mutableListOf<RemappedParameter>()
|
||||
if (function.dispatchReceiverParameter != null && includeDispatcherReceiver) {
|
||||
val template = ValueParameterTemplate(
|
||||
name = "\$dispatchReceiver",
|
||||
@@ -161,7 +161,24 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
return newFlattenedParameters
|
||||
}
|
||||
|
||||
val bindingParameterTemplateStructure: MutableMap<IrFunction, List<List<ValueParameterTemplate>>> = ConcurrentHashMap()
|
||||
sealed class RemappedParameter {
|
||||
data class RegularMapping(val valueParameter: ValueParameterTemplate) : RemappedParameter() {
|
||||
override val valueParameters: List<ValueParameterTemplate> = listOf(valueParameter)
|
||||
}
|
||||
|
||||
data class MultiFieldValueClassMapping(
|
||||
val declarations: MultiFieldValueClassSpecificDeclarations,
|
||||
override val valueParameters: List<ValueParameterTemplate>,
|
||||
) : RemappedParameter() {
|
||||
init {
|
||||
require(valueParameters.size > 1) { "MFVC must have > 1 fields" }
|
||||
}
|
||||
}
|
||||
|
||||
abstract val valueParameters: List<ValueParameterTemplate>
|
||||
}
|
||||
|
||||
val bindingParameterTemplateStructure: MutableMap<IrFunction, List<RemappedParameter>> = ConcurrentHashMap()
|
||||
|
||||
override fun createStaticReplacement(function: IrFunction): IrSimpleFunction =
|
||||
buildReplacement(function, JvmLoweredDeclarationOrigin.STATIC_MULTI_FIELD_VALUE_CLASS_REPLACEMENT, noFakeOverride = true) {
|
||||
@@ -184,7 +201,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
original = receiver,
|
||||
) else null
|
||||
bindingParameterTemplateStructure[function] =
|
||||
if (receiverTemplate != null) listOf(listOf(receiverTemplate)) + newFlattenedParameters else newFlattenedParameters
|
||||
if (receiverTemplate != null) listOf(RemappedParameter.RegularMapping(receiverTemplate)) + newFlattenedParameters else newFlattenedParameters
|
||||
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
||||
}
|
||||
|
||||
@@ -217,7 +234,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
defaultValue = receiver.defaultValue,
|
||||
original = receiver
|
||||
)
|
||||
bindingParameterTemplateStructure[function] = listOf(listOf(receiverTemplate))
|
||||
bindingParameterTemplateStructure[function] = listOf(RemappedParameter.RegularMapping(receiverTemplate))
|
||||
return newGetter
|
||||
}
|
||||
|
||||
|
||||
+24
-3
@@ -35,8 +35,12 @@ value class E(val x: D) {
|
||||
set(_) = TODO()
|
||||
}
|
||||
|
||||
interface Base3 {
|
||||
val z: E
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class R<T : Any>(val x: Int, val y: UInt, val z: E, val t: A<T>)
|
||||
value class R<T : Any>(val x: Int, val y: UInt, override val z: E, val t: A<T>): Base1, Base3
|
||||
|
||||
fun <T : List<Int>> f(r: R<T>) {
|
||||
println(r)
|
||||
@@ -79,7 +83,20 @@ fun h1() {
|
||||
println(y)
|
||||
}
|
||||
|
||||
class NotInlined(var l: R<List<Int>>, var y: Int) {
|
||||
interface Base1 {
|
||||
val fakeOverrideMFVC: R<List<Int>>
|
||||
get() = TODO()
|
||||
val fakeOverrideRegular: Int
|
||||
get() = TODO()
|
||||
}
|
||||
interface Base2 {
|
||||
var l: R<List<Int>>
|
||||
}
|
||||
interface Base4<T> {
|
||||
var l: T
|
||||
}
|
||||
|
||||
class NotInlined(override var l: R<List<Int>>, var y: Int): Base1, Base2, Base4<R<List<Int>>> {
|
||||
override fun toString(): String = l.toString() + l.z.x.x.z
|
||||
|
||||
init {
|
||||
@@ -119,7 +136,7 @@ class NotInlined(var l: R<List<Int>>, var y: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
fun ekeke(x: NotInlined) {
|
||||
fun testVars(x: NotInlined) {
|
||||
x.l.toString()
|
||||
var y = x.l
|
||||
y.toString()
|
||||
@@ -129,6 +146,10 @@ fun ekeke(x: NotInlined) {
|
||||
x.l = R<List<Int>>(x.l.x, x.l.y, x.l.z, x.l.t)
|
||||
}
|
||||
|
||||
fun reuseBoxed(list: MutableList<R<List<Int>>>) {
|
||||
list.add(list.last())
|
||||
}
|
||||
|
||||
// todo add default parameters
|
||||
|
||||
fun box() = "bad"//.also { h(R(1, 2U, E(D(C(3, B(4U), "5"))), A(listOf(listOf(6))))) }
|
||||
|
||||
Reference in New Issue
Block a user