Bridge support
This commit is contained in:
@@ -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<CallableMemberDescriptor, Boolean>() {
|
||||
@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<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
|
||||
if (parameters.isEmpty()) {
|
||||
|
||||
@@ -33,4 +33,5 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
|
||||
interface JvmLoweredStatementOrigin : IrStatementOrigin {
|
||||
object DEFAULT_IMPLS_DELEGATION : IrStatementOriginImpl("DEFAULT_IMPL_DELEGATION")
|
||||
object BRIDGE_DELEGATION : IrStatementOriginImpl("BRIDGE_DELEGATION")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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) {
|
||||
|
||||
+23
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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<IrFunction>().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<CallableMemberDescriptor>() != null
|
||||
|
||||
val bridgesToGenerate: Set<Bridge<SignatureAndDescriptor>>
|
||||
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<CallableMemberDescriptor>()!!
|
||||
|
||||
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<FunctionDescriptor, SignatureAndDescriptor> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
fun FunctionDescriptor.isClInit(): Boolean = this.name == InitializersLowering.clinitName
|
||||
Reference in New Issue
Block a user