diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index a4cd0f20562..510ac53a431 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -764,7 +764,7 @@ public class FunctionCodegen { } } - private static boolean isThereOverriddenInKotlinClass(@NotNull CallableMemberDescriptor descriptor) { + public static boolean isThereOverriddenInKotlinClass(@NotNull CallableMemberDescriptor descriptor) { return CollectionsKt.any(getAllOverriddenDescriptors(descriptor), new Function1() { @Override public Boolean invoke(CallableMemberDescriptor descriptor) { @@ -784,7 +784,7 @@ public class FunctionCodegen { }; } - private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) { + public static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) { String name = descriptor.getName().asString(); List parameters = descriptor.getValueParameters(); if (parameters.isEmpty()) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt index ab27a21cca4..49f95812faa 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt @@ -33,4 +33,5 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin { interface JvmLoweredStatementOrigin : IrStatementOrigin { object DEFAULT_IMPLS_DELEGATION : IrStatementOriginImpl("DEFAULT_IMPL_DELEGATION") + object BRIDGE_DELEGATION : IrStatementOriginImpl("BRIDGE_DELEGATION") } \ No newline at end of file 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 f2fba8d6bc1..68a6f9f01bc 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 @@ -43,6 +43,7 @@ class JvmLower(val context: JvmBackendContext) { InitializersLowering(context).runOnFilePostfix(irFile) SingletonReferencesLowering(context).runOnFilePostfix(irFile) SyntheticAccessorLowering(context.state).lower(irFile) + BridgeLowering(context.state).runOnFilePostfix(irFile) } } 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 1f4995d6944..8ef778c8e4e 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 @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen +import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDescriptorWithExtraFlags import org.jetbrains.kotlin.backend.jvm.lower.InitializersLowering import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil.isStaticMethod @@ -58,7 +59,7 @@ class FunctionCodegen(val irFunction: IrFunction, val classCodegen: ClassCodegen var flags = AsmUtil.getMethodAsmFlags(descriptor, OwnerKind.IMPLEMENTATION, state).or(if (isStatic) Opcodes.ACC_STATIC else 0).xor( if (DescriptorUtils.isAnnotationClass(descriptor.containingDeclaration)) Opcodes.ACC_FINAL else 0/*TODO*/ - ) + ).or(if (descriptor is JvmDescriptorWithExtraFlags) descriptor.extraFlags else 0) val interfaceClInit = JvmCodegenUtil.isJvmInterface(classCodegen.descriptor) && InitializersLowering.clinitName == descriptor.name if (interfaceClInit) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDescriptorWithExtraFlags.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDescriptorWithExtraFlags.kt index 4928b2c0628..57b45692986 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDescriptorWithExtraFlags.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDescriptorWithExtraFlags.kt @@ -18,9 +18,12 @@ package org.jetbrains.kotlin.backend.jvm.descriptors import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.org.objectweb.asm.commons.Method interface JvmDescriptorWithExtraFlags { val extraFlags: Int @@ -85,4 +88,24 @@ class JvmPropertyDescriptorImpl( CallableMemberDescriptor.Kind.SYNTHESIZED, source, false, false ).initialize(type, dispatchReceiverParameter = classDescriptor.thisAsReceiverParameter) } +} + +class JvmFunctionDescriptorImpl( + containingDeclaration: DeclarationDescriptor, + original: FunctionDescriptor?, + annotations: Annotations, + name: Name, + kind: CallableMemberDescriptor.Kind, + source: SourceElement, + override val extraFlags: Int +) : JvmDescriptorWithExtraFlags, FunctionDescriptorImpl( + containingDeclaration, original, annotations, + name, kind, source +) { + override fun createSubstitutedCopy(newOwner: DeclarationDescriptor, original: FunctionDescriptor?, kind: CallableMemberDescriptor.Kind, newName: Name?, annotations: Annotations, source: SourceElement): FunctionDescriptorImpl { + return JvmFunctionDescriptorImpl( + newOwner, original, annotations, name, kind, + SourceElement.NO_SOURCE, extraFlags + ) + } } \ No newline at end of file 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 new file mode 100644 index 00000000000..17c7642b422 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -0,0 +1,239 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.jvm.lower + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.backend.common.bridges.Bridge +import org.jetbrains.kotlin.backend.common.bridges.findInterfaceImplementation +import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor +import org.jetbrains.kotlin.backend.jvm.ClassLoweringPass +import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin +import org.jetbrains.kotlin.backend.jvm.descriptors.DefaultImplsClassDescriptor +import org.jetbrains.kotlin.backend.jvm.descriptors.FileClassDescriptor +import org.jetbrains.kotlin.backend.jvm.descriptors.JvmFunctionDescriptorImpl +import org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityAccessFlag +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 +import org.jetbrains.kotlin.codegen.JvmCodegenUtil.getDirectMember +import org.jetbrains.kotlin.codegen.OwnerKind +import org.jetbrains.kotlin.codegen.state.GenerationState +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.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.load.java.BuiltinMethodsWithSpecialGenericSignature +import org.jetbrains.kotlin.load.java.getOverriddenBuiltinReflectingJvmDescriptor +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Opcodes.* +import org.jetbrains.org.objectweb.asm.commons.Method + +class BridgeLowering(val state: GenerationState) : ClassLoweringPass { + + val typeMapper = state.typeMapper + + private val IS_PURE_INTERFACE_CHECKER = fun(descriptor: DeclarationDescriptor): Boolean { + return JvmCodegenUtil.isAnnotationOrJvm6Interface(descriptor, state) + } + + override fun lower(irClass: IrClass) { + val classDescriptor = irClass.descriptor + if (JvmCodegenUtil.isAnnotationOrJvm6Interface(classDescriptor, state) || classDescriptor is FileClassDescriptor) return + + if (classDescriptor is DefaultImplsClassDescriptor) { + return /*TODO?*/ + } + + val functions = irClass.declarations.filterIsInstance().filterNot { + val descriptor = it.descriptor + descriptor is ConstructorDescriptor || + DescriptorUtils.isStaticDeclaration(descriptor) + } + + functions.forEach { + generateBridges(it.descriptor, irClass) + } + + + //additional bridges for interface methods + if (!DescriptorUtils.isInterface(classDescriptor) && classDescriptor !is DefaultImplsClassDescriptor) { + 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) + } + } + } + } + } + } + } + + + fun generateBridges(descriptor: FunctionDescriptor, irClass: IrClass) { + // equals(Any?), hashCode(), toString() never need bridges + if (isMethodOfAny(descriptor)) { + return + } + val isSpecial = descriptor.getOverriddenBuiltinReflectingJvmDescriptor() != null + + val bridgesToGenerate: Set> + if (!isSpecial) { + bridgesToGenerate = generateBridgesForFunctionDescriptor( + descriptor, + getSignatureMapper(typeMapper), + IS_PURE_INTERFACE_CHECKER + ) + 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), + IS_PURE_INTERFACE_CHECKER + ) + + 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, state)) { + val overridden = descriptor.getOverriddenBuiltinReflectingJvmDescriptor()!! + + if (!isThereOverriddenInKotlinClass(descriptor)) { + val method = typeMapper.mapAsmMethod(descriptor) + val flags = Opcodes.ACC_ABSTRACT or getVisibilityAccessFlag(descriptor) + //TODO + //v.newMethod(OtherOrigin(overridden!!), flags, method.name, method.descriptor, null, null) + } + } + } + } + + 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 newName = Name.identifier(bridge.method.name) + val newDescriptor = JvmFunctionDescriptorImpl(containingClass, null, Annotations.EMPTY, newName, CallableMemberDescriptor.Kind.SYNTHESIZED, descriptor.source, flags) + + val descriptorForBridge = bridge.descriptor + newDescriptor.initialize( + null, containingClass.thisAsReceiverParameter, emptyList(), + descriptorForBridge.valueParameters.map { it.copy(newDescriptor, it.name, it.index) }, + descriptorForBridge.returnType, Modality.OPEN, descriptor.visibility + ) + val irBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) + val irFunction = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, newDescriptor, irBody) + + //TODO + //MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv) +// if (delegateTo.method.argumentTypes.isNotEmpty() && isSpecialBridge) { +// generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()) +// } + + //TODO: rewrite + //here some 'isSpecialBridge' magic (see type special descriptor processing in KotlinTypeMapper) + val implementation = if (isSpecialBridge) delegateTo.descriptor.copyAsDeclaration() else delegateTo.descriptor + val call = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, implementation.returnType!!, implementation, null, JvmLoweredStatementOrigin.BRIDGE_DELEGATION, null) + call.dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, containingClass.thisAsReceiverParameter, JvmLoweredStatementOrigin.BRIDGE_DELEGATION) + newDescriptor.valueParameters.mapIndexed { i, valueParameterDescriptor -> + call.putValueArgument(i, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valueParameterDescriptor, JvmLoweredStatementOrigin.BRIDGE_DELEGATION)) + } + irBody.statements.add(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, newDescriptor.returnType!!, newDescriptor, call)) + + return irFunction + } + + companion object { + fun getSignatureMapper(typeMapper: KotlinTypeMapper): Function1 { + return fun(descriptor: FunctionDescriptor): SignatureAndDescriptor { + return SignatureAndDescriptor(typeMapper.mapAsmMethod(descriptor), descriptor) + } + } + + fun FunctionDescriptor.copyAsDeclaration(): FunctionDescriptor { + val isGetter = this is PropertyGetterDescriptor + val isAccessor = this is PropertyAccessorDescriptor + val directMember = getDirectMember(this) + val copy = directMember.copy(directMember.containingDeclaration, directMember.modality, directMember.visibility, DECLARATION, false) + if (isAccessor) { + val property = copy as PropertyDescriptor + return if (isGetter) property.getter!! else property.setter!! + } + return copy as FunctionDescriptor + } + } + + + class SignatureAndDescriptor(val method: Method, val descriptor: FunctionDescriptor) { + override fun equals(other: Any?): Boolean { + val sig2 = other as SignatureAndDescriptor + return method == sig2.method + } + + override fun hashCode(): Int { + return method.hashCode() + } + } + +} + diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/descriptorUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/descriptorUtils.kt index 63423b8acd7..2382eeb8fe6 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/descriptorUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/descriptorUtils.kt @@ -29,7 +29,7 @@ fun FunctionDescriptor.toStatic( ): FunctionDescriptor { val newFunction = SimpleFunctionDescriptorImpl.create( newOwner, AnnotationsImpl(emptyList()), - name, //Name.identifier(typeMapper.mapAsmMethod(this).name), + name, CallableMemberDescriptor.Kind.DECLARATION, this.source ) @@ -56,4 +56,6 @@ fun FunctionDescriptor.toStatic( valueParameters, returnType, Modality.FINAL, Visibilities.PUBLIC ) return newFunction -} \ No newline at end of file +} + +fun FunctionDescriptor.isClInit(): Boolean = this.name == InitializersLowering.clinitName \ No newline at end of file