Remove descriptors from BridgeLowering
This commit is contained in:
+4
-1
@@ -72,7 +72,10 @@ open class FunctionCodegen(private val irFunction: IrFunction, private val class
|
||||
val staticFlag = if (isStatic) Opcodes.ACC_STATIC else 0
|
||||
val varargFlag = if (irFunction.valueParameters.any { it.varargElementType != null }) Opcodes.ACC_VARARGS else 0
|
||||
val deprecation = if (irFunction.hasAnnotation(FQ_NAMES.deprecated)) Opcodes.ACC_DEPRECATED else 0
|
||||
val bridgeFlag = 0 //TODO
|
||||
val bridgeFlag = if (
|
||||
irFunction.origin == IrDeclarationOrigin.BRIDGE ||
|
||||
irFunction.origin == IrDeclarationOrigin.BRIDGE_SPECIAL
|
||||
) Opcodes.ACC_BRIDGE else 0
|
||||
val modalityFlag = when ((irFunction as? IrSimpleFunction)?.modality) {
|
||||
Modality.FINAL -> if (!classCodegen.irClass.isAnnotationClass || irFunction.isStatic) Opcodes.ACC_FINAL else Opcodes.ACC_ABSTRACT
|
||||
Modality.ABSTRACT -> Opcodes.ACC_ABSTRACT
|
||||
|
||||
+432
-282
@@ -5,55 +5,43 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge
|
||||
import org.jetbrains.kotlin.backend.common.bridges.findInterfaceImplementation
|
||||
import org.jetbrains.kotlin.backend.common.bridges.FunctionHandle
|
||||
import org.jetbrains.kotlin.backend.common.bridges.findAllReachableDeclarations
|
||||
import org.jetbrains.kotlin.backend.common.bridges.findConcreteSuperDeclaration
|
||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridges
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.lower.irNot
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.isAbstractMethod
|
||||
import org.jetbrains.kotlin.codegen.BuiltinSpecialBridgesUtil
|
||||
import org.jetbrains.kotlin.codegen.FunctionCodegen.isMethodOfAny
|
||||
import org.jetbrains.kotlin.codegen.FunctionCodegen.isThereOverriddenInKotlinClass
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil.getDirectMember
|
||||
import org.jetbrains.kotlin.codegen.OwnerKind
|
||||
import org.jetbrains.kotlin.codegen.generateBridgesForFunctionDescriptorForJvm
|
||||
import org.jetbrains.kotlin.codegen.isToArrayFromCollection
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.typeParametersCount
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.toIrType
|
||||
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
||||
import org.jetbrains.kotlin.load.java.getOverriddenBuiltinReflectingJvmDescriptor
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.getSuperClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
|
||||
internal val bridgePhase = makeIrFilePhase(
|
||||
@@ -69,286 +57,448 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
|
||||
private val typeMapper = state.typeMapper
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
val classDescriptor = irClass.descriptor
|
||||
if (irClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) {
|
||||
return /*TODO?*/
|
||||
}
|
||||
|
||||
val functions = irClass.declarations.filterIsInstance<IrFunction>().filterNot {
|
||||
val descriptor = it.descriptor
|
||||
descriptor is ConstructorDescriptor ||
|
||||
DescriptorUtils.isStaticDeclaration(descriptor) ||
|
||||
!descriptor.kind.isReal
|
||||
}
|
||||
|
||||
functions.forEach {
|
||||
generateBridges(it.descriptor, irClass)
|
||||
}
|
||||
|
||||
|
||||
//additional bridges for inherited interface methods
|
||||
if (!DescriptorUtils.isInterface(classDescriptor) && irClass.origin != JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) {
|
||||
for (memberDescriptor in DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope)) {
|
||||
if (memberDescriptor is CallableMemberDescriptor) {
|
||||
if (!memberDescriptor.kind.isReal && findInterfaceImplementation(memberDescriptor) == null) {
|
||||
if (memberDescriptor is FunctionDescriptor) {
|
||||
generateBridges(memberDescriptor, irClass)
|
||||
} else if (memberDescriptor is PropertyDescriptor) {
|
||||
val getter = memberDescriptor.getter
|
||||
if (getter != null) {
|
||||
generateBridges(getter, irClass)
|
||||
}
|
||||
val setter = memberDescriptor.setter
|
||||
if (setter != null) {
|
||||
generateBridges(setter, irClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun generateBridges(descriptor: FunctionDescriptor, irClass: IrClass) {
|
||||
// equals(Any?), hashCode(), toString() never need bridges
|
||||
if (isMethodOfAny(descriptor)) {
|
||||
// TODO: Bridges should be generated for @JvmDefaults, so the interface check is too optimistic.
|
||||
if (irClass.isInterface || irClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) {
|
||||
return
|
||||
}
|
||||
val isSpecial = descriptor.getOverriddenBuiltinReflectingJvmDescriptor<CallableMemberDescriptor>() != null
|
||||
|
||||
val bridgesToGenerate: Set<Bridge<SignatureAndDescriptor>>
|
||||
if (!isSpecial) {
|
||||
bridgesToGenerate = generateBridgesForFunctionDescriptorForJvm(
|
||||
descriptor,
|
||||
getSignatureMapper(typeMapper),
|
||||
state
|
||||
)
|
||||
if (!bridgesToGenerate.isEmpty()) {
|
||||
val origin = if (descriptor.kind == DECLARATION) getSourceFromDescriptor(descriptor) else null
|
||||
val isSpecialBridge =
|
||||
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor) != null
|
||||
|
||||
for (bridge in bridgesToGenerate) {
|
||||
irClass.declarations.add(createBridge(origin, descriptor, bridge.from, bridge.to, isSpecialBridge, false))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
|
||||
descriptor,
|
||||
getSignatureMapper(typeMapper),
|
||||
state
|
||||
)
|
||||
|
||||
if (!specials.isEmpty()) {
|
||||
val origin = if (descriptor.kind == DECLARATION) getSourceFromDescriptor(descriptor) else null
|
||||
for (bridge in specials) {
|
||||
irClass.declarations.add(
|
||||
createBridge(
|
||||
origin, descriptor, bridge.from, bridge.to,
|
||||
bridge.isSpecial, bridge.isDelegateToSuper
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!descriptor.kind.isReal && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) {
|
||||
descriptor.getOverriddenBuiltinReflectingJvmDescriptor<CallableMemberDescriptor>()
|
||||
?: error("Expect to find overridden descriptors for $descriptor")
|
||||
|
||||
if (!isThereOverriddenInKotlinClass(descriptor)) {
|
||||
// TODO: reimplement getVisibilityAccessFlag(descriptor)
|
||||
val visibility = if (descriptor.isToArrayFromCollection()) Visibilities.PUBLIC else descriptor.visibility
|
||||
val irFunction = IrFunctionImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
IrSimpleFunctionSymbolImpl(descriptor),
|
||||
returnType = descriptor.returnType!!.toIrType()!!,
|
||||
visibility = visibility,
|
||||
modality = Modality.ABSTRACT
|
||||
)
|
||||
irFunction.createParameterDeclarations()
|
||||
|
||||
irClass.declarations.add(irFunction)
|
||||
}
|
||||
}
|
||||
for (member in irClass.declarations.filterIsInstance<IrSimpleFunction>()) {
|
||||
createBridges(member)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBridge(
|
||||
origin: PsiElement?,
|
||||
descriptor: FunctionDescriptor,
|
||||
bridge: SignatureAndDescriptor,
|
||||
delegateTo: SignatureAndDescriptor,
|
||||
isSpecialBridge: Boolean,
|
||||
isStubDeclarationWithDelegationToSuper: Boolean
|
||||
): IrFunction {
|
||||
val isSpecialOrDelegationToSuper = isSpecialBridge || isStubDeclarationWithDelegationToSuper
|
||||
val flags =
|
||||
ACC_PUBLIC or ACC_BRIDGE or (if (!isSpecialOrDelegationToSuper) ACC_SYNTHETIC else 0) or if (isSpecialBridge) ACC_FINAL else 0 // TODO.
|
||||
val containingClass = descriptor.containingDeclaration as ClassDescriptor
|
||||
//here some 'isSpecialBridge' magic
|
||||
val bridgeDescriptorForIrFunction = JvmFunctionDescriptorImpl(
|
||||
containingClass, null, Annotations.EMPTY, Name.identifier(bridge.method.name),
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED, descriptor.source, flags
|
||||
)
|
||||
|
||||
bridgeDescriptorForIrFunction.initialize(
|
||||
bridge.descriptor.extensionReceiverParameter?.copy(bridgeDescriptorForIrFunction),
|
||||
containingClass.thisAsReceiverParameter, emptyList(),
|
||||
bridge.descriptor.valueParameters.map { it.copy(bridgeDescriptorForIrFunction, it.name, it.index) },
|
||||
bridge.descriptor.returnType, Modality.OPEN, descriptor.visibility
|
||||
)
|
||||
private fun createBridges(irFunction: IrSimpleFunction) {
|
||||
if (irFunction.isStatic) return
|
||||
if (irFunction.isMethodOfAny()) return
|
||||
|
||||
val returnType = bridgeDescriptorForIrFunction.returnType!!.toIrType()!!
|
||||
val irFunction = IrFunctionImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
IrDeclarationOrigin.BRIDGE,
|
||||
bridgeDescriptorForIrFunction,
|
||||
returnType
|
||||
)
|
||||
irFunction.createParameterDeclarations()
|
||||
|
||||
context.createIrBuilder(irFunction.symbol).irBlockBody(irFunction) {
|
||||
//TODO
|
||||
//MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv)
|
||||
if (delegateTo.method.argumentTypes.isNotEmpty() && isSpecialBridge) {
|
||||
generateTypeCheckBarrierIfNeeded(descriptor, bridgeDescriptorForIrFunction, irFunction, delegateTo.method.argumentTypes)
|
||||
}
|
||||
|
||||
val implementation = if (isSpecialBridge) delegateTo.copyAsDeclaration() else delegateTo.descriptor
|
||||
val call = IrCallImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
implementation.returnType!!.toIrType()!!,
|
||||
implementation,
|
||||
implementation.typeParametersCount,
|
||||
IrStatementOrigin.BRIDGE_DELEGATION,
|
||||
if (isStubDeclarationWithDelegationToSuper) getSuperClassDescriptor(
|
||||
descriptor.containingDeclaration as ClassDescriptor
|
||||
) else null
|
||||
)
|
||||
call.dispatchReceiver = IrGetValueImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
irFunction.dispatchReceiverParameter!!.symbol,
|
||||
IrStatementOrigin.BRIDGE_DELEGATION
|
||||
)
|
||||
irFunction.extensionReceiverParameter?.let {
|
||||
call.extensionReceiver = IrGetValueImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
it.symbol,
|
||||
IrStatementOrigin.BRIDGE_DELEGATION
|
||||
)
|
||||
}
|
||||
irFunction.valueParameters.mapIndexed { i, valueParameter ->
|
||||
call.putValueArgument(
|
||||
i,
|
||||
IrGetValueImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
valueParameter.symbol,
|
||||
IrStatementOrigin.BRIDGE_DELEGATION
|
||||
)
|
||||
)
|
||||
}
|
||||
+IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.returnType, irFunction.symbol, call)
|
||||
}.apply {
|
||||
irFunction.body = this
|
||||
if (irFunction.origin === IrDeclarationOrigin.FAKE_OVERRIDE &&
|
||||
irFunction.overriddenSymbols.all { it.owner.modality !== Modality.ABSTRACT && !it.owner.comesFromJava() }
|
||||
) {
|
||||
// All needed bridges will be generated where functions are implemented.
|
||||
return
|
||||
}
|
||||
|
||||
return irFunction
|
||||
}
|
||||
|
||||
private fun IrBlockBodyBuilder.generateTypeCheckBarrierIfNeeded(
|
||||
overrideDescriptor: FunctionDescriptor,
|
||||
bridgeDescriptor: FunctionDescriptor,
|
||||
bridgeFunction: IrFunction,
|
||||
delegateParameterTypes: Array<Type>?
|
||||
) {
|
||||
val typeSafeBarrierDescription =
|
||||
BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(overrideDescriptor) ?: return
|
||||
val irClass = irFunction.parentAsClass
|
||||
val ourSignature = irFunction.getJvmSignature()
|
||||
val ourMethodName = ourSignature.name
|
||||
|
||||
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(overrideDescriptor)
|
||||
?: error("Overridden built-in method should not be null for $overrideDescriptor")
|
||||
val (specialOverride, specialOverrideValueGenerator) =
|
||||
findSpecialWithOverride(irFunction) ?: Pair(null, null)
|
||||
val specialOverrideSignature = specialOverride?.getJvmSignature()
|
||||
|
||||
val conditions = bridgeDescriptor.valueParameters.withIndex().filter { (i, parameterDescriptor) ->
|
||||
typeSafeBarrierDescription.checkParameter(i) ||
|
||||
!(delegateParameterTypes == null || OBJECT_TYPE == delegateParameterTypes[i]) ||
|
||||
!TypeUtils.isNullableType(parameterDescriptor.type)
|
||||
}.map { (i, _) ->
|
||||
val checkValue =
|
||||
IrGetValueImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
bridgeFunction.valueParameters[i].symbol,
|
||||
IrStatementOrigin.BRIDGE_DELEGATION
|
||||
|
||||
var targetForCommonBridges = irFunction
|
||||
|
||||
// Special case: fake override redirecting to an implementation with a different JVM name,
|
||||
// or to a function with SpecialOverrideSignature.
|
||||
// TODO: we assume here that all implementations come from classes. There may be a default implementation in
|
||||
// an interface, If it comes from the same module, InterfaceDelegationLowering will build a redirection, and the following code will work.
|
||||
// But in an imported module, there will be no redirection => failure!
|
||||
if (irFunction.origin === IrDeclarationOrigin.FAKE_OVERRIDE &&
|
||||
irFunction.modality !== Modality.ABSTRACT &&
|
||||
irFunction.visibility !== Visibilities.INVISIBLE_FAKE &&
|
||||
irFunction.overriddenInClasses().firstOrNull { it.getJvmSignature() != ourSignature || it.origin != IrDeclarationOrigin.FAKE_OVERRIDE }
|
||||
?.let { (it.getJvmName() != ourMethodName || it.getJvmSignature() == specialOverrideSignature) && it.comesFromJava() } == true
|
||||
) {
|
||||
val resolved = irFunction.findConcreteSuperDeclaration()!!
|
||||
val resolvedSignature = resolved.getJvmSignature()
|
||||
if (!resolvedSignature.sameCallAs(ourSignature)) {
|
||||
val bridge = createBridgeHeader(irClass, resolved, irFunction, isSpecial = false, isSynthetic = false)
|
||||
bridge.createBridgeBody(resolved, null, isSpecial = false, invokeStatically = true)
|
||||
irClass.declarations.add(bridge)
|
||||
targetForCommonBridges = bridge
|
||||
}
|
||||
} else if (irFunction.origin == IrDeclarationOrigin.FAKE_OVERRIDE &&
|
||||
irFunction.modality == Modality.ABSTRACT &&
|
||||
irFunction.overriddenSymbols.all { it.owner.getJvmName() != ourMethodName }
|
||||
) {
|
||||
// Bridges for abstract fake overrides whose JVM names differ from overridden functions.
|
||||
val bridge = irFunction.orphanedCopy()
|
||||
irClass.declarations.add(bridge)
|
||||
targetForCommonBridges = bridge
|
||||
}
|
||||
|
||||
val signaturesToSkip = mutableSetOf(ourSignature)
|
||||
signaturesToSkip.addAll(getFinalOverridden(irFunction).map { it.getJvmSignature() })
|
||||
|
||||
val firstOverridden = irFunction.overriddenInClasses().firstOrNull()
|
||||
val firstOverriddenSignature = firstOverridden?.getJvmSignature()
|
||||
|
||||
val renamedOverridden = getRenamedOverridden(irFunction)
|
||||
if (renamedOverridden != null) {
|
||||
val renamer = irFunction.copyRenamingTo(Name.identifier(renamedOverridden.getJvmName()))
|
||||
// Renaming bridge may have already been generated in parent.
|
||||
if (firstOverridden == null || firstOverriddenSignature!!.name != ourMethodName || getRenamedOverridden(firstOverridden) == null) {
|
||||
addBridge(
|
||||
irClass, targetForCommonBridges, renamer, signaturesToSkip,
|
||||
defaultValueGenerator = null,
|
||||
isSpecial = true
|
||||
)
|
||||
if (delegateParameterTypes == null || OBJECT_TYPE == delegateParameterTypes[i]) {
|
||||
irNotEquals(checkValue, irNull())
|
||||
} else {
|
||||
irIs(checkValue, overrideDescriptor.valueParameters[i].type.toIrType()!!)
|
||||
// Renamer bridge in superclass.
|
||||
signaturesToSkip.add(renamer.getJvmSignature())
|
||||
}
|
||||
}
|
||||
|
||||
if (conditions.isNotEmpty()) {
|
||||
val condition = conditions.fold<IrExpression, IrExpression>(irTrue()) { arg, result ->
|
||||
context.andand(arg, result)
|
||||
}
|
||||
if (specialOverride != null && (firstOverridden == null || firstOverriddenSignature != ourSignature) &&
|
||||
specialOverrideSignature !in signaturesToSkip
|
||||
) {
|
||||
addBridge(
|
||||
irClass, targetForCommonBridges, specialOverride, signaturesToSkip,
|
||||
specialOverrideValueGenerator,
|
||||
isSpecial = true
|
||||
)
|
||||
}
|
||||
|
||||
+irIfThen(context.irBuiltIns.unitType, irNot(condition), irBlock {
|
||||
+irReturn(
|
||||
when (typeSafeBarrierDescription) {
|
||||
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT -> irGet(
|
||||
bridgeDescriptor.valueParameters[1].type.toIrType()!!,
|
||||
bridgeFunction.valueParameters[1].symbol
|
||||
val bridgeSignatures = generateBridges(
|
||||
FunctionHandleForIrFunction(irFunction),
|
||||
{ handle -> SignatureWithSource(handle.irFunction.getJvmSignature(), handle.irFunction) }
|
||||
)
|
||||
|
||||
for (bridgeSignature in bridgeSignatures) {
|
||||
val method = bridgeSignature.from.source
|
||||
addBridge(
|
||||
irClass, targetForCommonBridges, method, signaturesToSkip,
|
||||
defaultValueGenerator = null,
|
||||
isSpecial = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addBridge(
|
||||
irClass: IrClass,
|
||||
target: IrSimpleFunction,
|
||||
method: IrSimpleFunction,
|
||||
signaturesToSkip: MutableSet<Method>,
|
||||
defaultValueGenerator: ((IrSimpleFunction) -> IrExpression)?,
|
||||
isSpecial: Boolean
|
||||
) {
|
||||
val signature = method.getJvmSignature()
|
||||
if (signature in signaturesToSkip) return
|
||||
|
||||
val bridge = createBridgeHeader(irClass, target, method, isSpecial = isSpecial, isSynthetic = !isSpecial)
|
||||
bridge.createBridgeBody(target, defaultValueGenerator, isSpecial)
|
||||
irClass.declarations.add(bridge)
|
||||
signaturesToSkip.add(signature)
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.copyRenamingTo(newName: Name): IrSimpleFunction =
|
||||
WrappedSimpleFunctionDescriptor(descriptor.annotations).let { newDescriptor ->
|
||||
IrFunctionImpl(
|
||||
startOffset, endOffset, origin,
|
||||
IrSimpleFunctionSymbolImpl(newDescriptor),
|
||||
newName,
|
||||
visibility, modality, returnType,
|
||||
isInline, isExternal, isTailrec, isSuspend
|
||||
).apply {
|
||||
newDescriptor.bind(this)
|
||||
parent = this@copyRenamingTo.parent
|
||||
dispatchReceiverParameter = this@copyRenamingTo.dispatchReceiverParameter?.copyTo(this)
|
||||
extensionReceiverParameter = this@copyRenamingTo.extensionReceiverParameter?.copyTo(this)
|
||||
valueParameters.addAll(this@copyRenamingTo.valueParameters.map { it.copyTo(this) })
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBridgeHeader(
|
||||
irClass: IrClass,
|
||||
target: IrSimpleFunction,
|
||||
signatureFunction: IrSimpleFunction,
|
||||
isSpecial: Boolean,
|
||||
isSynthetic: Boolean
|
||||
): IrSimpleFunction {
|
||||
val modality = if (isSpecial) Modality.FINAL else Modality.OPEN
|
||||
val origin = if (isSynthetic) IrDeclarationOrigin.BRIDGE else IrDeclarationOrigin.BRIDGE_SPECIAL
|
||||
|
||||
val visibility = if (signatureFunction.visibility === Visibilities.INTERNAL) Visibilities.PUBLIC else signatureFunction.visibility
|
||||
val descriptor = WrappedSimpleFunctionDescriptor()
|
||||
return IrFunctionImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
origin,
|
||||
IrSimpleFunctionSymbolImpl(descriptor),
|
||||
Name.identifier(signatureFunction.getJvmName()),
|
||||
visibility,
|
||||
modality,
|
||||
returnType = signatureFunction.returnType.eraseTypeParameters(),
|
||||
isInline = false,
|
||||
isExternal = false,
|
||||
isTailrec = false,
|
||||
isSuspend = signatureFunction.isSuspend
|
||||
).apply {
|
||||
descriptor.bind(this)
|
||||
parent = irClass
|
||||
|
||||
// Have to specify type explicitly to prevent an attempt to remap it.
|
||||
dispatchReceiverParameter = irClass.thisReceiver?.copyTo(this, type = irClass.defaultType)
|
||||
extensionReceiverParameter = signatureFunction.extensionReceiverParameter
|
||||
?.copyWithTypeErasure(this)
|
||||
signatureFunction.valueParameters.mapIndexed { i, param ->
|
||||
valueParameters.add(i, param.copyWithTypeErasure(this))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.createBridgeBody(
|
||||
target: IrSimpleFunction,
|
||||
defaultValueGenerator: ((IrSimpleFunction) -> IrExpression)?,
|
||||
isSpecial: Boolean,
|
||||
invokeStatically: Boolean = false
|
||||
) {
|
||||
val maybeOrphanedTarget = if (isSpecial)
|
||||
target.orphanedCopy()
|
||||
else
|
||||
target
|
||||
|
||||
context.createIrBuilder(symbol).run {
|
||||
body = irBlockBody {
|
||||
if (defaultValueGenerator != null) {
|
||||
valueParameters.forEach {
|
||||
+irIfThen(
|
||||
context.irBuiltIns.unitType,
|
||||
irNot(irIs(irGet(it), maybeOrphanedTarget.valueParameters[it.index].type)),
|
||||
irReturn(defaultValueGenerator(this@createBridgeBody))
|
||||
)
|
||||
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.NULL -> irNull()
|
||||
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.INDEX -> IrConstImpl.int(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.intType, typeSafeBarrierDescription.defaultValue as Int
|
||||
)
|
||||
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.FALSE -> irFalse()
|
||||
}
|
||||
}
|
||||
+irReturn(
|
||||
irImplicitCast(
|
||||
IrCallImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
maybeOrphanedTarget.returnType,
|
||||
maybeOrphanedTarget.symbol, maybeOrphanedTarget.descriptor,
|
||||
origin = IrStatementOrigin.BRIDGE_DELEGATION,
|
||||
superQualifierSymbol = if (invokeStatically) maybeOrphanedTarget.parentAsClass.symbol else null
|
||||
).apply {
|
||||
dispatchReceiver = irImplicitCast(irGet(dispatchReceiverParameter!!), dispatchReceiverParameter!!.type)
|
||||
extensionReceiverParameter?.let {
|
||||
extensionReceiver = irImplicitCast(irGet(it), extensionReceiverParameter!!.type)
|
||||
}
|
||||
valueParameters.forEach {
|
||||
putValueArgument(it.index, irImplicitCast(irGet(it), maybeOrphanedTarget.valueParameters[it.index].type))
|
||||
}
|
||||
},
|
||||
returnType
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* A hacky way to make sure the code generator calls the right function, and not some standard interface it implements. */
|
||||
private fun IrSimpleFunction.orphanedCopy() =
|
||||
if (overriddenSymbols.size == 0)
|
||||
this
|
||||
else
|
||||
WrappedSimpleFunctionDescriptor(descriptor.annotations).let { wrappedDescriptor ->
|
||||
val newOrigin = if (origin == IrDeclarationOrigin.FAKE_OVERRIDE) IrDeclarationOrigin.DEFINED else origin
|
||||
IrFunctionImpl(
|
||||
startOffset, endOffset, newOrigin,
|
||||
IrSimpleFunctionSymbolImpl(wrappedDescriptor),
|
||||
Name.identifier(getJvmName()),
|
||||
visibility, modality, returnType,
|
||||
isInline, isExternal, isTailrec, isSuspend
|
||||
).apply {
|
||||
wrappedDescriptor.bind(this)
|
||||
parent = this@orphanedCopy.parent
|
||||
copyTypeParametersFrom(this@orphanedCopy)
|
||||
this@orphanedCopy.dispatchReceiverParameter?.let { dispatchReceiverParameter = it.copyTo(this) }
|
||||
this@orphanedCopy.extensionReceiverParameter?.let { extensionReceiverParameter = it.copyTo(this) }
|
||||
this@orphanedCopy.valueParameters.forEachIndexed { index, param ->
|
||||
valueParameters.add(index, param.copyTo(this))
|
||||
}
|
||||
/* Do NOT copy overriddenSymbols */
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getSignatureMapper(typeMapper: KotlinTypeMapper): Function1<FunctionDescriptor, SignatureAndDescriptor> {
|
||||
return fun(descriptor: FunctionDescriptor) =
|
||||
SignatureAndDescriptor(typeMapper.mapAsmMethod(descriptor), descriptor)
|
||||
}
|
||||
|
||||
fun SignatureAndDescriptor.copyAsDeclaration(): FunctionDescriptor {
|
||||
val containingClass = getDirectMember(descriptor).containingDeclaration as ClassDescriptor
|
||||
val delegationDescriptor = JvmFunctionDescriptorImpl(
|
||||
containingClass, null, Annotations.EMPTY, Name.identifier(method.name),
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED, descriptor.source, 0
|
||||
)
|
||||
|
||||
delegationDescriptor.initialize(
|
||||
descriptor.extensionReceiverParameter?.copy(delegationDescriptor), containingClass.thisAsReceiverParameter, emptyList(),
|
||||
descriptor.valueParameters.map { it.copy(delegationDescriptor, it.name, it.index) },
|
||||
descriptor.returnType, Modality.OPEN, descriptor.visibility
|
||||
)
|
||||
return delegationDescriptor
|
||||
private fun IrValueParameter.copyWithTypeErasure(target: IrSimpleFunction): IrValueParameter {
|
||||
val descriptor = WrappedValueParameterDescriptor(this.descriptor.annotations)
|
||||
return IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
IrDeclarationOrigin.BRIDGE,
|
||||
IrValueParameterSymbolImpl(descriptor),
|
||||
name,
|
||||
index,
|
||||
type.eraseTypeParameters(),
|
||||
varargElementType?.eraseTypeParameters(),
|
||||
isCrossinline,
|
||||
isNoinline
|
||||
).apply {
|
||||
descriptor.bind(this)
|
||||
parent = target
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SignatureAndDescriptor(val method: Method, val descriptor: FunctionDescriptor) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
val sig2 = other as SignatureAndDescriptor
|
||||
return method == sig2.method
|
||||
/* Perform type erasure as much as is significant for JVM signature generation. */
|
||||
// TODO: should be a type mapper functionality.
|
||||
private fun IrType.eraseTypeParameters() = when (this) {
|
||||
is IrErrorType -> this
|
||||
is IrSimpleType -> {
|
||||
val owner = classifier.owner
|
||||
when (owner) {
|
||||
is IrClass -> this
|
||||
is IrTypeParameter -> {
|
||||
val upperBound = owner.upperBoundClass()
|
||||
IrSimpleTypeImpl(
|
||||
upperBound.symbol,
|
||||
hasQuestionMark,
|
||||
List(upperBound.typeParameters.size) { IrStarProjectionImpl }, // Should not affect JVM signature, but may result in an invalid type object
|
||||
owner.annotations
|
||||
)
|
||||
}
|
||||
else -> error("Unknown IrSimpleType classifier kind: $owner")
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = method.hashCode()
|
||||
else -> error("Unknown IrType kind: $this")
|
||||
}
|
||||
|
||||
private fun IrTypeParameter.upperBoundClass(): IrClass {
|
||||
val simpleSuperClassifiers = superTypes.asSequence().filterIsInstance<IrSimpleType>().map { it.classifier }
|
||||
return simpleSuperClassifiers
|
||||
.filterIsInstance<IrClassSymbol>()
|
||||
.let {
|
||||
it.firstOrNull { !it.owner.isInterface } ?: it.firstOrNull()
|
||||
}?.owner ?:
|
||||
simpleSuperClassifiers.filterIsInstance<IrTypeParameterSymbol>().map { it.owner.upperBoundClass() }.firstOrNull() ?:
|
||||
context.irBuiltIns.anyClass.owner
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.findAllReachableDeclarations() =
|
||||
findAllReachableDeclarations(FunctionHandleForIrFunction(this)).map { it.irFunction }
|
||||
|
||||
private fun getFinalOverridden(irFunction: IrSimpleFunction): List<IrSimpleFunction> {
|
||||
return irFunction.findAllReachableDeclarations().filter { it.modality === Modality.FINAL }
|
||||
}
|
||||
|
||||
// There are two sources of method name change:
|
||||
// 1. Special methods renamed from java
|
||||
// 2. Internal methods overridden by public ones.
|
||||
// Here, we want to only deal with the first case.
|
||||
private fun getRenamedOverridden(irFunction: IrSimpleFunction): IrSimpleFunction? {
|
||||
val ourName = irFunction.getJvmName()
|
||||
return irFunction.allOverridden().firstOrNull {
|
||||
it.visibility == Visibilities.PUBLIC && it.getJvmName() != ourName
|
||||
}
|
||||
}
|
||||
|
||||
private data class SpecialMethodDescription(val kotlinFqClassName: FqName?, val name: Name, val arity: Int)
|
||||
|
||||
private fun makeDescription(classFqName: String, funName: String, arity: Int) = SpecialMethodDescription(FqName(classFqName), Name.identifier(funName), arity)
|
||||
|
||||
private fun IrSimpleFunction.toDescription() = SpecialMethodDescription(parentAsClass.fqName, name, valueParameters.size)
|
||||
|
||||
private fun constFalse(bridge: IrSimpleFunction) =
|
||||
IrConstImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.booleanType, IrConstKind.Boolean, false)
|
||||
|
||||
private fun constNull(bridge: IrSimpleFunction) =
|
||||
IrConstImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.anyNType, IrConstKind.Null, null)
|
||||
|
||||
private fun constMinusOne(bridge: IrSimpleFunction) =
|
||||
IrConstImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.intType, IrConstKind.Int, -1)
|
||||
|
||||
private fun getSecondArg(bridge: IrSimpleFunction) =
|
||||
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, bridge.valueParameters[1].symbol)
|
||||
|
||||
private val SPECIAL_METHODS_WITH_DEFAULTS_MAP = mapOf<SpecialMethodDescription, (IrSimpleFunction) -> IrExpression>(
|
||||
makeDescription("kotlin.collections.Collection", "contains", 1) to ::constFalse,
|
||||
makeDescription("kotlin.collections.MutableCollection", "remove", 1) to ::constFalse,
|
||||
makeDescription("kotlin.collections.Map", "containsKey", 1) to ::constFalse,
|
||||
makeDescription("kotlin.collections.Map", "containsValue", 1) to ::constFalse,
|
||||
makeDescription("kotlin.collections.MutableMap", "remove", 2) to ::constFalse,
|
||||
makeDescription("kotlin.collections.Map", "getOrDefault", 1) to ::getSecondArg,
|
||||
makeDescription("kotlin.collections.Map", "get", 1) to ::constNull,
|
||||
makeDescription("kotlin.collections.MutableMap", "remove", 1) to ::constNull,
|
||||
makeDescription("kotlin.collections.List", "indexOf", 1) to ::constMinusOne,
|
||||
makeDescription("kotlin.collections.List", "lastIndexOf", 1) to ::constMinusOne
|
||||
)
|
||||
|
||||
private fun findSpecialWithOverride(irFunction: IrSimpleFunction): Pair<IrSimpleFunction, (IrSimpleFunction) -> IrExpression>? {
|
||||
irFunction.allOverridden().forEach { overridden ->
|
||||
val description = overridden.toDescription()
|
||||
SPECIAL_METHODS_WITH_DEFAULTS_MAP[description]?.let {
|
||||
return Pair(overridden, it)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private inner class FunctionHandleForIrFunction(val irFunction: IrSimpleFunction) : FunctionHandle {
|
||||
override val isDeclaration get() = irFunction.origin != IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
override val isAbstract get() = irFunction.modality == Modality.ABSTRACT
|
||||
override val mayBeUsedAsSuperImplementation get() = !irFunction.parentAsClass.isInterface
|
||||
|
||||
override fun getOverridden() = irFunction.overriddenSymbols.map { FunctionHandleForIrFunction(it.owner) }
|
||||
|
||||
override fun hashCode(): Int =
|
||||
irFunction.parent.safeAs<IrClass>()?.fqName.hashCode() + 31 * irFunction.getJvmSignature().hashCode()
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is FunctionHandleForIrFunction &&
|
||||
irFunction.parent.safeAs<IrClass>()?.fqName == other.irFunction.parent.safeAs<IrClass>()?.fqName &&
|
||||
irFunction.getJvmSignature() == other.irFunction.getJvmSignature()
|
||||
}
|
||||
|
||||
fun IrSimpleFunction.findConcreteSuperDeclaration(): IrSimpleFunction? {
|
||||
return findConcreteSuperDeclaration(FunctionHandleForIrFunction(this))?.irFunction
|
||||
}
|
||||
|
||||
private fun IrFunction.getJvmSignature() = typeMapper.mapAsmMethod(descriptor)
|
||||
private fun IrFunction.getJvmName() = getJvmSignature().name
|
||||
}
|
||||
|
||||
private data class SignatureWithSource(val signature: Method, val source: IrSimpleFunction) {
|
||||
override fun hashCode(): Int {
|
||||
return signature.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other is SignatureWithSource && signature == other.signature
|
||||
}
|
||||
}
|
||||
|
||||
val IrClass.fqName
|
||||
get(): FqName? {
|
||||
val parentFqName = when (val parent = parent) {
|
||||
is IrPackageFragment -> parent.fqName
|
||||
is IrClass -> parent.fqName
|
||||
else -> return null
|
||||
}
|
||||
return parentFqName?.child(name)
|
||||
}
|
||||
|
||||
fun IrClass.isSubclassOf(pred: (IrClass) -> Boolean): Boolean =
|
||||
DFS.ifAny(
|
||||
listOf(this),
|
||||
DFS.Neighbors { current ->
|
||||
current.superTypes.mapNotNull { (it as? IrSimpleType)?.classifier?.owner as? IrClass }
|
||||
},
|
||||
pred
|
||||
)
|
||||
|
||||
fun IrSimpleFunction.allOverridden(): Sequence<IrSimpleFunction> {
|
||||
val visited = mutableSetOf<IrSimpleFunction>()
|
||||
|
||||
fun IrSimpleFunction.search(): Sequence<IrSimpleFunction> {
|
||||
if (this in visited) return emptySequence()
|
||||
return sequence {
|
||||
yield(this@search)
|
||||
visited.add(this@search)
|
||||
overriddenSymbols.forEach { yieldAll(it.owner.search()) }
|
||||
}
|
||||
}
|
||||
|
||||
return search().drop(1) // First element is `this`
|
||||
}
|
||||
|
||||
fun IrSimpleFunction.overriddenInClasses(): Sequence<IrSimpleFunction> =
|
||||
allOverridden().filter { !(it.parent.safeAs<IrClass>()?.isInterface ?: true) }
|
||||
|
||||
// TODO: At present, there is no reliable way to distinguish Java imports from Kotlin cross-module imports.
|
||||
val ORIGINS_FROM_JAVA = setOf(IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB, IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB)
|
||||
|
||||
fun IrDeclaration.comesFromJava() = parentAsClass.origin in ORIGINS_FROM_JAVA
|
||||
|
||||
// Method has the same name, same arguments as `other`. Return types may differ.
|
||||
fun Method.sameCallAs(other: Method) =
|
||||
name == other.name &&
|
||||
argumentTypes?.contentEquals(other.argumentTypes) == true
|
||||
|
||||
+5
-2
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
@@ -90,8 +91,10 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl
|
||||
}
|
||||
|
||||
val delegation = generateDelegationToDefaultImpl(irClass, implementation, function, isDefaultImplsGeneration)
|
||||
toRemove.add(function)
|
||||
replacementMap[function.symbol] = delegation.symbol
|
||||
if (!isDefaultImplsGeneration) {
|
||||
toRemove.add(function)
|
||||
replacementMap[function.symbol] = delegation.symbol
|
||||
}
|
||||
}
|
||||
irClass.declarations.removeAll(toRemove)
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ interface IrDeclarationOrigin {
|
||||
object IR_EXTERNAL_DECLARATION_STUB : IrDeclarationOriginImpl("IR_EXTERNAL_DECLARATION_STUB")
|
||||
object IR_EXTERNAL_JAVA_DECLARATION_STUB : IrDeclarationOriginImpl("IR_EXTERNAL_JAVA_DECLARATION_STUB")
|
||||
object IR_BUILTINS_STUB : IrDeclarationOriginImpl("IR_BUILTINS_STUB")
|
||||
object BRIDGE : IrDeclarationOriginImpl("BRIDGE")
|
||||
object BRIDGE : IrDeclarationOriginImpl("BRIDGE", isSynthetic = true)
|
||||
object BRIDGE_SPECIAL: IrDeclarationOriginImpl("BRIDGE_SPECIAL")
|
||||
|
||||
object FIELD_FOR_ENUM_ENTRY : IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRY")
|
||||
object FIELD_FOR_ENUM_VALUES : IrDeclarationOriginImpl("FIELD_FOR_ENUM_VALUES")
|
||||
|
||||
Reference in New Issue
Block a user