diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt index fc5f15fb642..6f27eb29691 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt @@ -49,7 +49,8 @@ object CodegenUtil { } @JvmStatic - fun getNonPrivateTraitMethods(descriptor: ClassDescriptor): Map { + @JvmOverloads + fun getNonPrivateTraitMethods(descriptor: ClassDescriptor, copy: Boolean = true): Map { val result = linkedMapOf() for (declaration in DescriptorUtils.getAllDescriptors(descriptor.defaultType.memberScope)) { if (declaration !is CallableMemberDescriptor) continue @@ -63,29 +64,39 @@ object CodegenUtil { // inheritedMember can be abstract here. In order for FunctionCodegen to generate the method body, we're creating a copy here // with traitMember's modality - result.putAll(copyFunctions(declaration, traitMember, declaration.containingDeclaration, traitMember.modality, - Visibilities.PUBLIC, CallableMemberDescriptor.Kind.DECLARATION, true)) + result.putAll( + if (copy) + copyFunctions( + declaration, traitMember, declaration.containingDeclaration, traitMember.modality, + Visibilities.PUBLIC, CallableMemberDescriptor.Kind.DECLARATION, true + ) + else mapMembers(declaration, traitMember) + ) } return result } fun copyFunctions( - inheritedMember: CallableMemberDescriptor, - traitMember: CallableMemberDescriptor, - newOwner: DeclarationDescriptor, - modality: Modality, - visibility: Visibility, - kind: CallableMemberDescriptor.Kind, - copyOverrides: Boolean - ): Map { - val copy = inheritedMember.copy(newOwner, modality, visibility, kind, copyOverrides) + inheritedMember: CallableMemberDescriptor, + traitMember: CallableMemberDescriptor, + newOwner: DeclarationDescriptor, + modality: Modality, + visibility: Visibility, + kind: CallableMemberDescriptor.Kind, + copyOverrides: Boolean + ): Map = + mapMembers(inheritedMember.copy(newOwner, modality, visibility, kind, copyOverrides), traitMember) + + private fun mapMembers( + inherited: CallableMemberDescriptor, + traitMember: CallableMemberDescriptor + ): LinkedHashMap { val result = linkedMapOf() if (traitMember is SimpleFunctionDescriptor) { - result[traitMember] = copy as FunctionDescriptor - } - else if (traitMember is PropertyDescriptor) { + result[traitMember] = inherited as FunctionDescriptor + } else if (traitMember is PropertyDescriptor) { for (traitAccessor in traitMember.accessors) { - for (inheritedAccessor in (copy as PropertyDescriptor).accessors) { + for (inheritedAccessor in (inherited as PropertyDescriptor).accessors) { if (inheritedAccessor::class.java == traitAccessor::class.java) { // same accessor kind result.put(traitAccessor, inheritedAccessor) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index 92c6a274d36..7d34c9979df 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -34,7 +34,7 @@ class JvmBackendContext( irModuleFragment: IrModuleFragment, symbolTable: SymbolTable ) : CommonBackendContext { override val builtIns = state.module.builtIns - override val declarationFactory: JvmDeclarationFactory = JvmDeclarationFactory(psiSourceManager, builtIns) + override val declarationFactory: JvmDeclarationFactory = JvmDeclarationFactory(psiSourceManager, builtIns, state) override val sharedVariablesManager = JvmSharedVariablesManager(builtIns, irBuiltIns) override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 802e17f0980..badda28fab2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -41,8 +41,8 @@ class JvmLower(val context: JvmBackendContext) { //Should be before interface lowering DefaultArgumentStubGenerator(context, false).runOnFilePostfix(irFile) - InterfaceLowering(context.state).runOnFilePostfix(irFile) - InterfaceDelegationLowering(context.state).runOnFilePostfix(irFile) + InterfaceLowering(context).runOnFilePostfix(irFile) + InterfaceDelegationLowering(context).runOnFilePostfix(irFile) SharedVariablesLowering(context).runOnFilePostfix(irFile) irFile.acceptVoid(PatchDeclarationParentsVisitor()) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt index 564c57029c1..29e79a87095 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt @@ -7,17 +7,23 @@ package org.jetbrains.kotlin.backend.jvm.descriptors import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.backend.jvm.lower.createFunctionAndMapVariables +import org.jetbrains.kotlin.backend.jvm.lower.createStaticFunctionWithReceivers import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl @@ -29,7 +35,10 @@ import org.jetbrains.kotlin.ir.types.toIrType import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.dump +import org.jetbrains.kotlin.ir.util.isInterface +import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.load.java.JavaVisibilities +import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.resolve.source.KotlinSourceElement @@ -38,12 +47,16 @@ import java.util.* class JvmDeclarationFactory( private val psiSourceManager: PsiSourceManager, - private val builtIns: KotlinBuiltIns + private val builtIns: KotlinBuiltIns, + private val state: GenerationState ) : DeclarationFactory { private val singletonFieldDeclarations = HashMap() private val outerThisDeclarations = HashMap() private val innerClassConstructors = HashMap() + private val defaultImplsMethods = HashMap() + private val defaultImplsClasses = HashMap() + override fun getFieldForEnumEntry(enumEntry: IrEnumEntry, type: IrType): IrField = singletonFieldDeclarations.getOrPut(enumEntry) { val symbol = IrFieldSymbolImpl(createEnumEntryFieldDescriptor(enumEntry.descriptor)) @@ -186,4 +199,44 @@ class JvmDeclarationFactory( /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false, /* isDelegated = */ false ).initialize(objectDescriptor.defaultType) } + + fun getDefaultImplsFunction(interfaceFun: IrFunction): IrFunction { + assert(interfaceFun.parentAsClass.isInterface) { "Parent of ${interfaceFun.dump()} should be interface" } + return defaultImplsMethods.getOrPut(interfaceFun) { + val defaultImpls = getDefaultImplsClass(interfaceFun.parentAsClass) + + createDefaultImplFunDescriptor( + defaultImpls.descriptor as DefaultImplsClassDescriptor, + interfaceFun.descriptor.original, + interfaceFun.parentAsClass.descriptor, + state.typeMapper + ).createFunctionAndMapVariables(interfaceFun, origin = JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) + } + } + + fun getDefaultImplsClass(interfaceClass: IrClass): IrClass = + defaultImplsClasses.getOrPut(interfaceClass) { + IrClassImpl( + interfaceClass.startOffset, interfaceClass.endOffset, JvmLoweredDeclarationOrigin.DEFAULT_IMPLS, + createDefaultImplsClassDescriptor(interfaceClass.descriptor) + ) + } + + companion object { + + private fun createDefaultImplsClassDescriptor(interfaceDescriptor: ClassDescriptor): DefaultImplsClassDescriptorImpl { + return DefaultImplsClassDescriptorImpl( + Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME), interfaceDescriptor, interfaceDescriptor.source + ) + } + + private fun createDefaultImplFunDescriptor( + defaultImplsDescriptor: DefaultImplsClassDescriptor, + descriptor: FunctionDescriptor, + interfaceDescriptor: ClassDescriptor, typeMapper: KotlinTypeMapper + ): SimpleFunctionDescriptorImpl { + val name = Name.identifier(typeMapper.mapAsmMethod(descriptor).name) + return createStaticFunctionWithReceivers(defaultImplsDescriptor, name, descriptor, interfaceDescriptor.defaultType) + } + } } 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 218f2a8cd05..083a3f25533 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 @@ -7,79 +7,92 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.CodegenUtil +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.descriptors.DefaultImplsClassDescriptor -import org.jetbrains.kotlin.backend.jvm.descriptors.DefaultImplsClassDescriptorImpl +import org.jetbrains.kotlin.codegen.FunctionCodegen import org.jetbrains.kotlin.codegen.isDefinitelyNotDefaultImplsMethod import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET 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.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl 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.types.toIrType import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -class InterfaceDelegationLowering(val state: GenerationState) : IrElementTransformerVoid(), ClassLoweringPass { +class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass { + + val state: GenerationState = context.state override fun lower(irClass: IrClass) { if (irClass.isJvmInterface) return irClass.transformChildrenVoid(this) - generateInterfaceMethods(irClass, irClass.descriptor) + generateInterfaceMethods(irClass) } - private fun generateInterfaceMethods(irClass: IrClass, descriptor: ClassDescriptor) { - val classDescriptor = (descriptor as? DefaultImplsClassDescriptor)?.correspondingInterface ?: descriptor - for ((interfaceFun, value) in CodegenUtil.getNonPrivateTraitMethods(classDescriptor)) { + private fun generateInterfaceMethods(irClass: IrClass) { + val irClassDescriptor = irClass.descriptor + val actualClassDescriptor = (irClassDescriptor as? DefaultImplsClassDescriptor)?.correspondingInterface ?: irClassDescriptor + val isDefaultImplsGeneration = actualClassDescriptor !== irClassDescriptor + for ((interfaceFun, value) in CodegenUtil.getNonPrivateTraitMethods(actualClassDescriptor, !isDefaultImplsGeneration)) { //skip java 8 default methods - if (!interfaceFun.isDefinitelyNotDefaultImplsMethod()) { - val inheritedFun = - if (classDescriptor !== descriptor) { - InterfaceLowering.createDefaultImplFunDescriptor( - descriptor as DefaultImplsClassDescriptorImpl, - interfaceFun, - classDescriptor, - state.typeMapper - ) - } else { - value - } - generateDelegationToDefaultImpl(irClass, interfaceFun, inheritedFun) + if (!interfaceFun.isDefinitelyNotDefaultImplsMethod() && !FunctionCodegen.isMethodOfAny(interfaceFun)) { + generateDelegationToDefaultImpl( + irClass, context.ir.symbols.externalSymbolTable.referenceSimpleFunction( + interfaceFun.original + ).owner, value, isDefaultImplsGeneration + ) } } } - private fun generateDelegationToDefaultImpl(irClass: IrClass, interfaceFun: FunctionDescriptor, inheritedFun: FunctionDescriptor) { + private fun generateDelegationToDefaultImpl( + irClass: IrClass, + interfaceFun: IrFunction, + inheritedFun: FunctionDescriptor, + isDefaultImplsGeneration: Boolean + ) { + val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(interfaceFun) + + val irFunction = + if (!isDefaultImplsGeneration) IrFunctionImpl( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + IrDeclarationOrigin.DEFINED, + inheritedFun, + null + ).also { + it.createParameterDeclarations() + it.returnType = defaultImplFun.returnType + } + else context.declarationFactory.getDefaultImplsFunction( + context.ir.symbols.externalSymbolTable.referenceSimpleFunction( + inheritedFun.original + ).owner + ) val irBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) - val irFunction = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, inheritedFun, irBody) - irFunction.createParameterDeclarations() + irFunction.body = irBody irClass.declarations.add(irFunction) - val interfaceDescriptor = interfaceFun.containingDeclaration as ClassDescriptor - val defaultImpls = InterfaceLowering.createDefaultImplsClassDescriptor(interfaceDescriptor) - val defaultImplFun = - InterfaceLowering.createDefaultImplFunDescriptor(defaultImpls, interfaceFun.original, interfaceDescriptor, state.typeMapper) - irFunction.returnType = defaultImplFun.returnType!!.toIrType()!! val irCallImpl = IrCallImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - defaultImplFun.returnType!!.toIrType()!!, - defaultImplFun, - defaultImplFun.typeParametersCount, - JvmLoweredStatementOrigin.DEFAULT_IMPLS_DELEGATION + defaultImplFun.returnType, + defaultImplFun.symbol, + defaultImplFun.descriptor, + origin = JvmLoweredStatementOrigin.DEFAULT_IMPLS_DELEGATION ) irBody.statements.add( IrReturnImpl(