JVM_IR. Cache defaultImpls function declarations

This commit is contained in:
Mikhael Bogdanov
2018-08-30 10:51:38 +02:00
committed by romanart
parent 5c0cdac69f
commit 92ce50b22c
5 changed files with 131 additions and 54 deletions
@@ -49,7 +49,8 @@ object CodegenUtil {
}
@JvmStatic
fun getNonPrivateTraitMethods(descriptor: ClassDescriptor): Map<FunctionDescriptor, FunctionDescriptor> {
@JvmOverloads
fun getNonPrivateTraitMethods(descriptor: ClassDescriptor, copy: Boolean = true): Map<FunctionDescriptor, FunctionDescriptor> {
val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>()
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<FunctionDescriptor, FunctionDescriptor> {
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<FunctionDescriptor, FunctionDescriptor> =
mapMembers(inheritedMember.copy(newOwner, modality, visibility, kind, copyOverrides), traitMember)
private fun mapMembers(
inherited: CallableMemberDescriptor,
traitMember: CallableMemberDescriptor
): LinkedHashMap<FunctionDescriptor, FunctionDescriptor> {
val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>()
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)
}
@@ -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) {
@@ -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())
@@ -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<IrSymbolOwner, IrField>()
private val outerThisDeclarations = HashMap<IrClass, IrField>()
private val innerClassConstructors = HashMap<IrConstructor, IrConstructor>()
private val defaultImplsMethods = HashMap<IrFunction, IrFunction>()
private val defaultImplsClasses = HashMap<IrClass, IrClass>()
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)
}
}
}
@@ -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(