JVM_IR. Mostly remove descriptors from InterfaceDelegationLowering

This commit is contained in:
Georgy Bronnikov
2018-10-28 08:22:34 +03:00
parent cbc46fe6e4
commit 1764423860
2 changed files with 83 additions and 32 deletions
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.lower.createStaticFunctionWithReceivers
import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -191,7 +192,7 @@ class JvmDeclarationFactory(
return defaultImplsMethods.getOrPut(interfaceFun) {
val defaultImpls = getDefaultImplsClass(interfaceFun.parentAsClass)
val name = Name.identifier(state.typeMapper.mapAsmMethod(interfaceFun.descriptor.original).name)
val name = Name.identifier(state.typeMapper.mapFunctionName(interfaceFun.descriptor.original, OwnerKind.IMPLEMENTATION))
createStaticFunctionWithReceivers(
defaultImpls, name, interfaceFun,
dispatchReceiverType = parent.defaultType,
@@ -6,29 +6,35 @@
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.common.makePhase
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
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.codegen.FunctionCodegen
import org.jetbrains.kotlin.codegen.isDefinitelyNotDefaultImplsMethod
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
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.IrSimpleFunction
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.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.name.Name
class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
@@ -43,44 +49,67 @@ class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementTra
private fun generateInterfaceMethods(irClass: IrClass) {
val irClassDescriptor = irClass.descriptor
val actualClassDescriptor = (irClass.takeIf { it.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS }?.parent as? IrClass)?.descriptor ?: irClassDescriptor
val isDefaultImplsGeneration = actualClassDescriptor !== irClassDescriptor
for ((interfaceFun, value) in CodegenUtil.getNonPrivateTraitMethods(actualClassDescriptor, !isDefaultImplsGeneration)) {
val (actualClass, isDefaultImplsGeneration) = if (irClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) {
Pair(irClass.parent as IrClass, true)
} else {
Pair(irClass, false)
}
for ((interfaceFun, value) in actualClass.getNonPrivateInterfaceMethods()) {
//skip java 8 default methods
if (!interfaceFun.isDefinitelyNotDefaultImplsMethod() && !FunctionCodegen.isMethodOfAny(interfaceFun)) {
generateDelegationToDefaultImpl(
irClass, context.ir.symbols.externalSymbolTable.referenceSimpleFunction(
interfaceFun.original
).owner, value, isDefaultImplsGeneration
)
if (!interfaceFun.isDefinitelyNotDefaultImplsMethod() && !interfaceFun.isMethodOfAny()) {
generateDelegationToDefaultImpl(irClass, interfaceFun, value, isDefaultImplsGeneration)
}
}
// CodegenUtil.getNonPrivateTraitMethods(actualClass.descriptor, !isDefaultImplsGeneration)) {
// //skip java 8 default methods
// if (!interfaceFun.isDefinitelyNotDefaultImplsMethod() && !FunctionCodegen.isMethodOfAny(interfaceFun)) {
// generateDelegationToDefaultImpl(
// irClass, context.ir.symbols.externalSymbolTable.referenceSimpleFunction(
// interfaceFun.original
// ).owner, value, isDefaultImplsGeneration
// )
// }
// }
}
private fun generateDelegationToDefaultImpl(
irClass: IrClass,
interfaceFun: IrFunction,
inheritedFun: FunctionDescriptor,
inheritedFun: IrSimpleFunction,
isDefaultImplsGeneration: Boolean
) {
val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(interfaceFun)
val irFunction =
if (!isDefaultImplsGeneration) IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
IrDeclarationOrigin.DEFINED,
inheritedFun,
defaultImplFun.returnType
).also {
it.createParameterDeclarations()
}
else context.declarationFactory.getDefaultImplsFunction(
context.ir.symbols.externalSymbolTable.referenceSimpleFunction(
inheritedFun.original
).owner
)
if (!isDefaultImplsGeneration) {
val descriptor = WrappedSimpleFunctionDescriptor(inheritedFun.descriptor.annotations, inheritedFun.descriptor.source)
/*
By using WrappedDescriptor, we lose information whether the function is an accessor.
`KotlinTypeMapper` needs that info to generate JVM name.
TODO: streamline name generation.
*/
val name = Name.identifier(context.state.typeMapper.mapFunctionName(inheritedFun.descriptor, OwnerKind.IMPLEMENTATION))
IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(descriptor),
name,
Visibilities.PUBLIC,
inheritedFun.modality,
isInline = inheritedFun.isInline,
isExternal = false,
isTailrec = false,
isSuspend = inheritedFun.isSuspend
).apply {
descriptor.bind(this)
parent = inheritedFun.parent
returnType = inheritedFun.returnType
overriddenSymbols.addAll(inheritedFun.overriddenSymbols)
copyParameterDeclarationsFrom(inheritedFun)
}
} else context.declarationFactory.getDefaultImplsFunction(inheritedFun)
val irBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
irFunction.body = irBody
irClass.declarations.add(irFunction)
@@ -126,4 +155,25 @@ class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementTra
}
}
private fun IrSimpleFunction.isMethodOfAny() =
((valueParameters.size == 0 && name.asString() in setOf("hashCode", "toString")) ||
(valueParameters.size == 1 && name.asString() == "equals" && valueParameters[0].type == context.irBuiltIns.anyType))
private fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod() =
resolveFakeOverride()?.let {
origin == IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB && descriptor is JavaCallableMemberDescriptor
} == true ||
hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME)
private fun IrClass.getNonPrivateInterfaceMethods(): List<Pair<IrSimpleFunction, IrSimpleFunction>> {
return declarations.filterIsInstance<IrSimpleFunction>().mapNotNull { function ->
val resolved = function.resolveFakeOverride()
resolved?.takeIf {
resolved !== function && // TODO: take a better look
(resolved.parent as? IrClass)?.isInterface == true &&
!Visibilities.isPrivate(resolved.visibility) &&
resolved.visibility != Visibilities.INVISIBLE_FAKE
}?.let { Pair(resolved, function) }
}
}
}