Remove descriptors from BridgeLowering

This commit is contained in:
Georgy Bronnikov
2018-12-04 00:29:20 +03:00
parent c9b8f58a10
commit 72ea4cc3d7
8 changed files with 443 additions and 290 deletions
@@ -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
@@ -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
@@ -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")
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
interface A {
fun foo(): Any
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
abstract class A1<Q> : MutableCollection<Q> {
override fun contains(o: Q): Boolean {
throw UnsupportedOperationException()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
interface A {
fun foo() = 42
}