diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index 0dfcae605f4..2f43b3c9309 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt index cbfc39184e3..e657d8c30d5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -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().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() != null - val bridgesToGenerate: Set> - 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() - ?: 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()) { + 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? - ) { - 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(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, + 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 { - 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().map { it.classifier } + return simpleSuperClassifiers + .filterIsInstance() + .let { + it.firstOrNull { !it.owner.isInterface } ?: it.firstOrNull() + }?.owner ?: + simpleSuperClassifiers.filterIsInstance().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 { + 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 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 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()?.fqName.hashCode() + 31 * irFunction.getJvmSignature().hashCode() + + override fun equals(other: Any?): Boolean = + other is FunctionHandleForIrFunction && + irFunction.parent.safeAs()?.fqName == other.irFunction.parent.safeAs()?.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 { + val visited = mutableSetOf() + + fun IrSimpleFunction.search(): Sequence { + 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 = + allOverridden().filter { !(it.parent.safeAs()?.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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt index 2e00fe88224..c5fd931b0d5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt @@ -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) } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index fbf81f1224f..4ab1746ca97 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -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") diff --git a/compiler/testData/codegen/box/specialBuiltins/mapGetOrDefault.kt b/compiler/testData/codegen/box/specialBuiltins/mapGetOrDefault.kt index 355c9415261..6df54b0c16f 100644 --- a/compiler/testData/codegen/box/specialBuiltins/mapGetOrDefault.kt +++ b/compiler/testData/codegen/box/specialBuiltins/mapGetOrDefault.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_RUNTIME diff --git a/compiler/testData/codegen/bytecodeText/bridgeForFakeOverride.kt b/compiler/testData/codegen/bytecodeText/bridgeForFakeOverride.kt index dccc5337bb6..2f481c74fc3 100644 --- a/compiler/testData/codegen/bytecodeText/bridgeForFakeOverride.kt +++ b/compiler/testData/codegen/bytecodeText/bridgeForFakeOverride.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR interface A { fun foo(): Any } diff --git a/compiler/testData/codegen/bytecodeText/builtinFunctions/contains.kt b/compiler/testData/codegen/bytecodeText/builtinFunctions/contains.kt index a24316cbea6..4422a29be04 100644 --- a/compiler/testData/codegen/bytecodeText/builtinFunctions/contains.kt +++ b/compiler/testData/codegen/bytecodeText/builtinFunctions/contains.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR abstract class A1 : MutableCollection { override fun contains(o: Q): Boolean { throw UnsupportedOperationException() diff --git a/compiler/testData/codegen/bytecodeText/interfaces/traitImplGeneratedOnce.kt b/compiler/testData/codegen/bytecodeText/interfaces/traitImplGeneratedOnce.kt index e0bb2a2c8b1..e308c0d92dc 100644 --- a/compiler/testData/codegen/bytecodeText/interfaces/traitImplGeneratedOnce.kt +++ b/compiler/testData/codegen/bytecodeText/interfaces/traitImplGeneratedOnce.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR interface A { fun foo() = 42 }