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 @JvmStatic
fun getNonPrivateTraitMethods(descriptor: ClassDescriptor): Map<FunctionDescriptor, FunctionDescriptor> { @JvmOverloads
fun getNonPrivateTraitMethods(descriptor: ClassDescriptor, copy: Boolean = true): Map<FunctionDescriptor, FunctionDescriptor> {
val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>() val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>()
for (declaration in DescriptorUtils.getAllDescriptors(descriptor.defaultType.memberScope)) { for (declaration in DescriptorUtils.getAllDescriptors(descriptor.defaultType.memberScope)) {
if (declaration !is CallableMemberDescriptor) continue 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 // inheritedMember can be abstract here. In order for FunctionCodegen to generate the method body, we're creating a copy here
// with traitMember's modality // with traitMember's modality
result.putAll(copyFunctions(declaration, traitMember, declaration.containingDeclaration, traitMember.modality, result.putAll(
Visibilities.PUBLIC, CallableMemberDescriptor.Kind.DECLARATION, true)) if (copy)
copyFunctions(
declaration, traitMember, declaration.containingDeclaration, traitMember.modality,
Visibilities.PUBLIC, CallableMemberDescriptor.Kind.DECLARATION, true
)
else mapMembers(declaration, traitMember)
)
} }
return result return result
} }
fun copyFunctions( fun copyFunctions(
inheritedMember: CallableMemberDescriptor, inheritedMember: CallableMemberDescriptor,
traitMember: CallableMemberDescriptor, traitMember: CallableMemberDescriptor,
newOwner: DeclarationDescriptor, newOwner: DeclarationDescriptor,
modality: Modality, modality: Modality,
visibility: Visibility, visibility: Visibility,
kind: CallableMemberDescriptor.Kind, kind: CallableMemberDescriptor.Kind,
copyOverrides: Boolean copyOverrides: Boolean
): Map<FunctionDescriptor, FunctionDescriptor> { ): Map<FunctionDescriptor, FunctionDescriptor> =
val copy = inheritedMember.copy(newOwner, modality, visibility, kind, copyOverrides) mapMembers(inheritedMember.copy(newOwner, modality, visibility, kind, copyOverrides), traitMember)
private fun mapMembers(
inherited: CallableMemberDescriptor,
traitMember: CallableMemberDescriptor
): LinkedHashMap<FunctionDescriptor, FunctionDescriptor> {
val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>() val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>()
if (traitMember is SimpleFunctionDescriptor) { if (traitMember is SimpleFunctionDescriptor) {
result[traitMember] = copy as FunctionDescriptor result[traitMember] = inherited as FunctionDescriptor
} } else if (traitMember is PropertyDescriptor) {
else if (traitMember is PropertyDescriptor) {
for (traitAccessor in traitMember.accessors) { 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 if (inheritedAccessor::class.java == traitAccessor::class.java) { // same accessor kind
result.put(traitAccessor, inheritedAccessor) result.put(traitAccessor, inheritedAccessor)
} }
@@ -34,7 +34,7 @@ class JvmBackendContext(
irModuleFragment: IrModuleFragment, symbolTable: SymbolTable irModuleFragment: IrModuleFragment, symbolTable: SymbolTable
) : CommonBackendContext { ) : CommonBackendContext {
override val builtIns = state.module.builtIns 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 sharedVariablesManager = JvmSharedVariablesManager(builtIns, irBuiltIns)
override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) { override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
@@ -41,8 +41,8 @@ class JvmLower(val context: JvmBackendContext) {
//Should be before interface lowering //Should be before interface lowering
DefaultArgumentStubGenerator(context, false).runOnFilePostfix(irFile) DefaultArgumentStubGenerator(context, false).runOnFilePostfix(irFile)
InterfaceLowering(context.state).runOnFilePostfix(irFile) InterfaceLowering(context).runOnFilePostfix(irFile)
InterfaceDelegationLowering(context.state).runOnFilePostfix(irFile) InterfaceDelegationLowering(context).runOnFilePostfix(irFile)
SharedVariablesLowering(context).runOnFilePostfix(irFile) SharedVariablesLowering(context).runOnFilePostfix(irFile)
irFile.acceptVoid(PatchDeclarationParentsVisitor()) 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.common.ir.DeclarationFactory
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin 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.CompanionObjectMapping.isMappedIntrinsicCompanionObject
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor 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.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.* 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.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl 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.types.toKotlinType
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.dump 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.JavaVisibilities
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.psi2ir.PsiSourceManager
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
@@ -38,12 +47,16 @@ import java.util.*
class JvmDeclarationFactory( class JvmDeclarationFactory(
private val psiSourceManager: PsiSourceManager, private val psiSourceManager: PsiSourceManager,
private val builtIns: KotlinBuiltIns private val builtIns: KotlinBuiltIns,
private val state: GenerationState
) : DeclarationFactory { ) : DeclarationFactory {
private val singletonFieldDeclarations = HashMap<IrSymbolOwner, IrField>() private val singletonFieldDeclarations = HashMap<IrSymbolOwner, IrField>()
private val outerThisDeclarations = HashMap<IrClass, IrField>() private val outerThisDeclarations = HashMap<IrClass, IrField>()
private val innerClassConstructors = HashMap<IrConstructor, IrConstructor>() 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 = override fun getFieldForEnumEntry(enumEntry: IrEnumEntry, type: IrType): IrField =
singletonFieldDeclarations.getOrPut(enumEntry) { singletonFieldDeclarations.getOrPut(enumEntry) {
val symbol = IrFieldSymbolImpl(createEnumEntryFieldDescriptor(enumEntry.descriptor)) val symbol = IrFieldSymbolImpl(createEnumEntryFieldDescriptor(enumEntry.descriptor))
@@ -186,4 +199,44 @@ class JvmDeclarationFactory(
/* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false, /* isDelegated = */ false /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false, /* isDelegated = */ false
).initialize(objectDescriptor.defaultType) ).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.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.CodegenUtil 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.JvmLoweredStatementOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.backend.jvm.descriptors.DefaultImplsClassDescriptor 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.isDefinitelyNotDefaultImplsMethod
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin 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.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl 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.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid 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) { override fun lower(irClass: IrClass) {
if (irClass.isJvmInterface) return if (irClass.isJvmInterface) return
irClass.transformChildrenVoid(this) irClass.transformChildrenVoid(this)
generateInterfaceMethods(irClass, irClass.descriptor) generateInterfaceMethods(irClass)
} }
private fun generateInterfaceMethods(irClass: IrClass, descriptor: ClassDescriptor) { private fun generateInterfaceMethods(irClass: IrClass) {
val classDescriptor = (descriptor as? DefaultImplsClassDescriptor)?.correspondingInterface ?: descriptor val irClassDescriptor = irClass.descriptor
for ((interfaceFun, value) in CodegenUtil.getNonPrivateTraitMethods(classDescriptor)) { val actualClassDescriptor = (irClassDescriptor as? DefaultImplsClassDescriptor)?.correspondingInterface ?: irClassDescriptor
val isDefaultImplsGeneration = actualClassDescriptor !== irClassDescriptor
for ((interfaceFun, value) in CodegenUtil.getNonPrivateTraitMethods(actualClassDescriptor, !isDefaultImplsGeneration)) {
//skip java 8 default methods //skip java 8 default methods
if (!interfaceFun.isDefinitelyNotDefaultImplsMethod()) { if (!interfaceFun.isDefinitelyNotDefaultImplsMethod() && !FunctionCodegen.isMethodOfAny(interfaceFun)) {
val inheritedFun = generateDelegationToDefaultImpl(
if (classDescriptor !== descriptor) { irClass, context.ir.symbols.externalSymbolTable.referenceSimpleFunction(
InterfaceLowering.createDefaultImplFunDescriptor( interfaceFun.original
descriptor as DefaultImplsClassDescriptorImpl, ).owner, value, isDefaultImplsGeneration
interfaceFun, )
classDescriptor,
state.typeMapper
)
} else {
value
}
generateDelegationToDefaultImpl(irClass, interfaceFun, inheritedFun)
} }
} }
} }
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 irBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
val irFunction = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, inheritedFun, irBody) irFunction.body = irBody
irFunction.createParameterDeclarations()
irClass.declarations.add(irFunction) 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 = val irCallImpl =
IrCallImpl( IrCallImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
defaultImplFun.returnType!!.toIrType()!!, defaultImplFun.returnType,
defaultImplFun, defaultImplFun.symbol,
defaultImplFun.typeParametersCount, defaultImplFun.descriptor,
JvmLoweredStatementOrigin.DEFAULT_IMPLS_DELEGATION origin = JvmLoweredStatementOrigin.DEFAULT_IMPLS_DELEGATION
) )
irBody.statements.add( irBody.statements.add(
IrReturnImpl( IrReturnImpl(