diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index bd2d9398769..c918bb99ca4 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -5,7 +5,10 @@ import llvm.LLVMModuleRef import org.jetbrains.kotlin.backend.jvm.descriptors.initialize import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.ir.Ir -import org.jetbrains.kotlin.backend.konan.llvm.* +import org.jetbrains.kotlin.backend.konan.llvm.Llvm +import org.jetbrains.kotlin.backend.konan.llvm.LlvmDeclarations +import org.jetbrains.kotlin.backend.konan.llvm.functionName +import org.jetbrains.kotlin.backend.konan.llvm.verifyModule import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl @@ -20,7 +23,7 @@ import java.lang.System.out internal class SpecialDescriptorsFactory(val context: Context) { private val outerThisDescriptors = mutableMapOf() - private val bridgesDescriptors = mutableMapOf() + private val bridgesDescriptors = mutableMapOf, FunctionDescriptor>() fun getOuterThisFieldDescriptor(innerClassDescriptor: ClassDescriptor): PropertyDescriptor = if (!innerClassDescriptor.isInner) throw AssertionError("Class is not inner: $innerClassDescriptor") @@ -34,24 +37,25 @@ internal class SpecialDescriptorsFactory(val context: Context) { false, false, false, false, false, false).initialize(outerClassDescriptor.defaultType, dispatchReceiverParameter = receiver) } - fun getBridgeDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor { - return bridgesDescriptors.getOrPut(descriptor) { + fun getBridgeDescriptor(descriptor: OverriddenFunctionDescriptor): FunctionDescriptor { + val bridgeDirections = descriptor.bridgeDirections + assert(descriptor.needBridge, + { "Function ${descriptor.descriptor} is not needed in a bridge to call overridden function ${descriptor.overriddenDescriptor}" }) + return bridgesDescriptors.getOrPut(descriptor.descriptor to bridgeDirections) { SimpleFunctionDescriptorImpl.create( - descriptor.containingDeclaration, + descriptor.descriptor.containingDeclaration, Annotations.EMPTY, - ("" + descriptor.functionName).synthesizedName, + ("" + descriptor.descriptor.functionName).synthesizedName, CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE).apply { - initializeBridgeDescriptor(this, descriptor) + initializeBridgeDescriptor(this, descriptor.descriptor, bridgeDirections.array) } } } - private fun initializeBridgeDescriptor(bridgeDescriptor: SimpleFunctionDescriptorImpl, descriptor: FunctionDescriptor) { - val bridgeDirections = descriptor.bridgeDirections - if (bridgeDirections.allNotNeeded()) - throw AssertionError("Function $descriptor is not needed in a bridge") - + private fun initializeBridgeDescriptor(bridgeDescriptor: SimpleFunctionDescriptorImpl, + descriptor: FunctionDescriptor, + bridgeDirections: Array) { val returnType = when (bridgeDirections[0]) { BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!! BridgeDirection.NOT_NEEDED -> descriptor.returnType @@ -66,7 +70,7 @@ internal class SpecialDescriptorsFactory(val context: Context) { bridgeDescriptor.initialize( extensionReceiverType, - descriptor.dispatchReceiverParameter, + (descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter, descriptor.typeParameters, descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor -> when (bridgeDirections[index + 2]) { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt index c066e9fbc8c..f86c26ed993 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt @@ -15,19 +15,50 @@ internal class OverriddenFunctionDescriptor(val descriptor: FunctionDescriptor, val needBridge: Boolean get() { if (descriptor.modality == Modality.ABSTRACT) return false - return descriptor.needBridgeTo(overriddenDescriptor) + return descriptor.kind == CallableMemberDescriptor.Kind.DELEGATION + //|| descriptor.needBridgeTo(overriddenDescriptor) || descriptor.target.needBridgeTo(overriddenDescriptor) } fun trivialOverride() = descriptor.original == overriddenDescriptor + val bridgeDirections: BridgeDirections + get() { +// if (descriptor.needBridgeTo(overriddenDescriptor)) +// return descriptor.bridgeDirectionsTo(overriddenDescriptor) + return descriptor.target.bridgeDirectionsTo(overriddenDescriptor) + } + + val canBeCalledVirtually + // We check that either method is open, or one of declarations it overrides is open. + get() = overriddenDescriptor.isOverridable || DescriptorUtils.getAllOverriddenDeclarations(overriddenDescriptor).any { it.isOverridable } + + override fun toString(): String { return "(descriptor=$descriptor, overriddenDescriptor=$overriddenDescriptor)" } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is OverriddenFunctionDescriptor) return false + + if (descriptor != other.descriptor) return false + if (overriddenDescriptor != other.overriddenDescriptor) return false + + return true + } + + override fun hashCode(): Int { + var result = descriptor.hashCode() + result = 31 * result + overriddenDescriptor.hashCode() + return result + } } internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val context: Context) { - val vtableEntries: List by lazy { + val vtableEntries: List /*by lazy*/ get() { + + println("VTABLE_ENTRIES class: $classDescriptor") assert(!classDescriptor.isInterface) @@ -53,21 +84,64 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con } } - methods.filterNot { method -> inheritedVtableSlots.any { it.descriptor == method } } // Find newly defined methods. - // Select target because method might be taken from default implementation of interface. - .mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it.target) } + println("VTABLE_ENTRIES inherited vtable:") + inheritedVtableSlots.forEach { + println(" VTABLE_ENTRIES descriptor: ${it.descriptor}") + println(" VTABLE_ENTRIES overriddenDescriptor: ${it.overriddenDescriptor}") + println(" VTABLE_ENTRIES needBridge: ${it.needBridge}") + if (it.needBridge) + println(" VTABLE_ENTRIES bridgeDirections: ${it.bridgeDirections.toString()}") + } + println() - val list = inheritedVtableSlots + newVtableSlots.filter { it.descriptor.isOverridable }.sortedBy { - it.overriddenDescriptor.functionName.localHash.value + // TODO: why put all pairs ? + val zzz = inheritedVtableSlots.map { it.descriptor to it.bridgeDirections }.toSet() + + methods// Find newly defined methods. + // TODO: Select target because method might be taken from default implementation of interface. + .mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it) } + + val filteredNewVtableSlots = newVtableSlots + .filter { (it.descriptor.kind.isReal || it.needBridge) && !zzz.contains(it.descriptor to it.bridgeDirections) } + .distinctBy { it.descriptor to it.bridgeDirections } + .filter { it.descriptor.isOverridable } + println("VTABLE_ENTRIES new vtable:") + filteredNewVtableSlots.forEach { + println(" VTABLE_ENTRIES descriptor: ${it.descriptor}") + println(" VTABLE_ENTRIES overriddenDescriptor: ${it.overriddenDescriptor}") + println(" VTABLE_ENTRIES needBridge: ${it.needBridge}") + if (it.needBridge) + println(" VTABLE_ENTRIES bridgeDirections: ${it.bridgeDirections.toString()}") } - list + println() + + + val list = inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.functionName.localHash.value } + + println("VTABLE_ENTRIES vtable:") + list.forEach { + println(" VTABLE_ENTRIES descriptor: ${it.descriptor}") + println(" VTABLE_ENTRIES overriddenDescriptor: ${it.overriddenDescriptor}") + println(" VTABLE_ENTRIES needBridge: ${it.needBridge}") + if (it.needBridge) + println(" VTABLE_ENTRIES bridgeDirections: ${it.bridgeDirections.toString()}") + } + println() + println() + + + return list } fun vtableIndex(function: FunctionDescriptor): Int { val target = function.target - val index = vtableEntries.indexOfFirst { it.overriddenDescriptor == target } + println("VTABLE_INDEX function: $function") + println("VTABLE_INDEX original: ${function.original}") + println("VTABLE_INDEX target: ${target}") + println("VTABLE_INDEX bridgeDirections: ${target.bridgeDirectionsTo(function.original).toString()}") + val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == target.bridgeDirectionsTo(function.original) } if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString()) - return index + return index.apply { println("VTABLE_INDEX index: $this"); println() } } private val ClassDescriptor.contributedMethodsWithOverridden: List @@ -81,14 +155,26 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con } } - val methodTableEntries: List by lazy { + val methodTableEntries: List /*by lazy*/ get() { assert(!classDescriptor.isAbstract()) - classDescriptor.contributedMethodsWithOverridden.filter { - // We check that either method is open, or one of declarations it overrides - // is open. - it.overriddenDescriptor.isOverridable || DescriptorUtils.getAllOverriddenDeclarations(it.overriddenDescriptor).any { it.isOverridable } - } + println("METHOD_TABLE_ENTRIES: class = $this") + + val contributedMethodsWithOverridden = classDescriptor.contributedMethodsWithOverridden + println("METHOD_TABLE_ENTRIES: contributed methods") + contributedMethodsWithOverridden.forEach { + println(" METHOD_TABLE_ENTRIES: descriptor = ${it.descriptor}") + println(" METHOD_TABLE_ENTRIES: overriddenDescriptor = ${it.overriddenDescriptor}") + println(" METHOD_TABLE_ENTRIES: overriddenDescriptor.isOverridable = ${it.overriddenDescriptor.isOverridable}") + } + val result = contributedMethodsWithOverridden.filter { it.canBeCalledVirtually } + + println("METHOD_TABLE_ENTRIES: result") + result.forEach { + println(" METHOD_TABLE_ENTRIES: descriptor = ${it.descriptor}") + println(" METHOD_TABLE_ENTRIES: overriddenDescriptor = ${it.overriddenDescriptor}") + } + return result // TODO: probably method table should contain all accessible methods to improve binary compatibility } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt index 46142597e43..399f3faff2e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.util.OperatorNameConventions +import java.util.* /** * List of all implemented interfaces (including those which implemented by a super class) @@ -49,6 +50,7 @@ internal fun T.resolveFakeOverride(): T { val overridden = OverridingUtil.getOverriddenDeclarations(this) val filtered = OverridingUtil.filterOutOverridden(overridden) // TODO: is it correct to take first? + @Suppress("UNCHECKED_CAST") return filtered.first { it.modality != Modality.ABSTRACT } as T } } @@ -166,6 +168,7 @@ internal val T.allOverriddenDescriptors: List val result = mutableListOf() fun traverse(descriptor: T) { result.add(descriptor) + @Suppress("UNCHECKED_CAST") descriptor.overriddenDescriptors.forEach { traverse(it as T) } } traverse(this) @@ -209,12 +212,6 @@ internal fun FunctionDescriptor.hasReferenceAt(index: Int): Boolean { } } -private fun FunctionDescriptor.overridesFunWithReferenceAt(index: Int) - = allOverriddenDescriptors.any { it.original.hasReferenceAt(index) } - -private fun FunctionDescriptor.overridesFunWithValueTypeAt(index: Int) - = allOverriddenDescriptors.any { it.original.hasValueTypeAt(index) } - private fun FunctionDescriptor.needBridgeToAt(target: FunctionDescriptor, index: Int) = hasValueTypeAt(index) xor target.hasValueTypeAt(index) @@ -230,39 +227,52 @@ internal enum class BridgeDirection { TO_VALUE_TYPE } -private fun FunctionDescriptor.bridgeDirectionAt(index: Int) : BridgeDirection { - if (kind.isReal) { - if (hasValueTypeAt(index) && overridesFunWithReferenceAt(index)) - return BridgeDirection.FROM_VALUE_TYPE - return BridgeDirection.NOT_NEEDED - } - - val target = this.target - return when { - hasValueTypeAt(index) && target.hasValueTypeAt(index) && overridesFunWithReferenceAt(index) -> BridgeDirection.FROM_VALUE_TYPE - hasValueTypeAt(index) && target.hasReferenceAt(index) && overridesFunWithValueTypeAt(index) -> BridgeDirection.TO_VALUE_TYPE - else -> BridgeDirection.NOT_NEEDED +private fun FunctionDescriptor.bridgeDirectionToAt(target: FunctionDescriptor, index: Int): BridgeDirection { + when { + hasValueTypeAt(index) && target.hasReferenceAt(index) -> return BridgeDirection.FROM_VALUE_TYPE + hasReferenceAt(index) && target.hasValueTypeAt(index) -> return BridgeDirection.TO_VALUE_TYPE + else -> return BridgeDirection.NOT_NEEDED } } -private fun bridgesEqual(first: Array, second: Array) - = first.indices.none { first[it] != second[it] } +internal class BridgeDirections(val array: Array) { + constructor(parametersCount: Int): this(Array(parametersCount + 2, { BridgeDirection.NOT_NEEDED })) -internal fun Array.allNotNeeded() = this.all { it == BridgeDirection.NOT_NEEDED } + fun allNotNeeded(): Boolean = array.all { it == BridgeDirection.NOT_NEEDED } -internal val FunctionDescriptor.bridgeDirections: Array - get() { - val ourDirections = Array(this.valueParameters.size + 2, { BridgeDirection.NOT_NEEDED }) - if (modality == Modality.ABSTRACT) - return ourDirections - for (index in ourDirections.indices) - ourDirections[index] = this.bridgeDirectionAt(index) - - if (!kind.isReal && bridgesEqual(ourDirections, this.target.bridgeDirections)) { - // Bridge is inherited from supers - for (index in ourDirections.indices) - ourDirections[index] = BridgeDirection.NOT_NEEDED - } - - return ourDirections + override fun toString(): String { + return String(array.map { + when (it) { + BridgeDirection.FROM_VALUE_TYPE -> 'U' // unbox + BridgeDirection.TO_VALUE_TYPE -> 'B' // box + BridgeDirection.NOT_NEEDED -> 'N' // none + } + }.toCharArray()) } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is BridgeDirections) return false + + return (Arrays.equals(array, other.array)) + } + + override fun hashCode(): Int { + return Arrays.hashCode(array) + } +} + +internal fun FunctionDescriptor.bridgeDirectionsTo(overriddenDescriptor: FunctionDescriptor): BridgeDirections { + val ourDirections = BridgeDirections(this.valueParameters.size) + if (modality == Modality.ABSTRACT) + return ourDirections + for (index in ourDirections.array.indices) + ourDirections.array[index] = this.bridgeDirectionToAt(overriddenDescriptor, index) + + if (!kind.isReal && OverridingUtil.overrides(this.target, overriddenDescriptor) && ourDirections == this.target.bridgeDirectionsTo(overriddenDescriptor)) { + // Bridge is inherited from supers + return BridgeDirections(this.valueParameters.size) + } + + return ourDirections +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt index 9390564aa71..1f703419295 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt @@ -6,6 +6,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny @@ -121,6 +122,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { val fieldsPtr = staticData.placeGlobalConstArray("kfields:$className", runtime.fieldTableRecordType, fields) + println("GEN_TABLES: class = $classDesc") val methods = if (classDesc.isAbstract()) { emptyList() } else { @@ -133,7 +135,10 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { throw AssertionError("Duplicate method table entry: functionName = '$functionName', hash = '${nameSignature.value}', entry1 = $previous, entry2 = $it") // TODO: compile-time resolution limits binary compatibility - val methodEntryPoint = it.implementation.entryPointAddress + val implementation = it.implementation + println("METHOD_TABLE: function = $functionName") + println("METHOD_TABLE: impl = $implementation") + val methodEntryPoint = implementation.entryPointAddress MethodTableRecord(nameSignature, methodEntryPoint) }.sortedBy { it.nameSignature.value } } @@ -154,7 +159,11 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { typeInfo } else { // TODO: compile-time resolution limits binary compatibility - val vtableEntries = context.getVtableBuilder(classDesc).vtableEntries.map { it.implementation.entryPointAddress } + val vtableEntries = context.getVtableBuilder(classDesc).vtableEntries.map { + val implementation = it.implementation + println("RAW_VTABLE: impl = $implementation") + implementation.entryPointAddress + } val vtable = ConstArray(int8TypePtr, vtableEntries) Struct(typeInfo, vtable) } @@ -167,9 +176,14 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { internal val OverriddenFunctionDescriptor.implementation: FunctionDescriptor get() { + println("IMPLEMENTATION fun: ${descriptor}") + println("IMPLEMENTATION overridden: ${overriddenDescriptor}") val target = descriptor.target + println("IMPLEMENTATION target: ${target}") if (!needBridge) return target - val bridgeOwner = if (descriptor.bridgeDirections.allNotNeeded()) target else descriptor - return context.specialDescriptorsFactory.getBridgeDescriptor(bridgeOwner) + //val bridgeOwner = if (!descriptor.kind.isReal && OverridingUtil.overrides(target, overriddenDescriptor) && !descriptor.needBridgeTo(overriddenDescriptor)) if (descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()) target else descriptor + val bridgeOwner = if (!descriptor.kind.isReal && OverridingUtil.overrides(target, overriddenDescriptor) && descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()) target else descriptor + println("IMPLEMENTATION owner: ${bridgeOwner}") + return context.specialDescriptorsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor)) } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt index 5f29fe36887..a4b4bdc5efc 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt @@ -91,38 +91,6 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr } } - override fun visitCall(expression: IrCall): IrExpression { - val irCall = super.visitCall(expression) as IrCall - - val descriptor = irCall.descriptor as? FunctionDescriptor ?: return irCall - if (descriptor.modality == Modality.ABSTRACT || (irCall.superQualifier == null && descriptor.isOverridable)) - return irCall // A virtual call. box/unbox will be in the corresponding bridge. - - val target = descriptor.target - - if (!descriptor.original.needBridgeTo(target)) return irCall - - val overriddenCall = IrCallImpl(irCall.startOffset, irCall.endOffset, - target, remapTypeArguments(irCall, target)).apply { - dispatchReceiver = irCall.dispatchReceiver - extensionReceiver = irCall.extensionReceiver - mapValueParameters { irCall.getValueArgument(it)!! } - } - - return super.visitCall(overriddenCall) - } - - private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: CallableDescriptor): Map? { - val oldCallee = oldExpression.descriptor - - return if (oldCallee.typeParameters.isEmpty()) - null - else oldCallee.typeParameters.associateBy( - { newCallee.typeParameters[it.index] }, - { oldExpression.getTypeArgument(it)!! } - ) - } - /** * @return the [ValueType] given type represented in generated code as, * or `null` if represented as object reference. diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt index 6515a234a98..1baed157f66 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt @@ -1,63 +1,108 @@ package org.jetbrains.kotlin.backend.konan.lower -import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.BodyLoweringPass +import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET -import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrProperty 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.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.types.typeUtil.isUnit +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.types.KotlinType -internal class BridgesBuilding(val context: Context) : FileLoweringPass { - override fun lower(irFile: IrFile) { - irFile.transformChildrenVoid(object : IrElementTransformerVoid() { - - override fun visitClass(declaration: IrClass): IrStatement { - val irClass = super.visitClass(declaration) as IrClass - - val functions = mutableSetOf() - irClass.declarations.forEach { - when (it) { - is IrFunction -> functions.add(it.descriptor) - is IrProperty -> { - functions.add(it.getter?.descriptor) - functions.add(it.setter?.descriptor) - } - } +internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPass { + override fun lower(irBody: IrBody) { + irBody.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + val descriptor = expression.descriptor as? FunctionDescriptor ?: return expression + if (descriptor.modality == Modality.ABSTRACT + || (expression.superQualifier == null && descriptor.isOverridable)) { + // A virtual call. box/unbox will be in the corresponding bridge. + return expression } - irClass.descriptor.contributedMethods.forEach { functions.add(it) } + val target = descriptor.target + if (descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION && !descriptor.original.needBridgeTo(target)) + return expression - functions.forEach { buildBridge(it, irClass) } + return IrCallImpl(expression.startOffset, expression.endOffset, + target, remapTypeArguments(expression, target)).apply { + dispatchReceiver = expression.dispatchReceiver + extensionReceiver = expression.extensionReceiver + mapValueParameters { expression.getValueArgument(it)!! } + } + } - return irClass + private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: CallableDescriptor) + : Map? { + val oldCallee = oldExpression.descriptor + + return if (oldCallee.typeParameters.isEmpty()) + null + else oldCallee.typeParameters.associateBy( + { newCallee.typeParameters[it.index] }, + { oldExpression.getTypeArgument(it)!! } + ) } }) + } +} +internal class BridgesBuilding(val context: Context) : ClassLoweringPass { + override fun lower(irClass: IrClass) { + val functions = mutableSetOf() + irClass.declarations.forEach { + when (it) { + is IrFunction -> functions.add(it.descriptor) + is IrProperty -> { + functions.add(it.getter?.descriptor) + functions.add(it.setter?.descriptor) + } + } + } + + irClass.descriptor.contributedMethods.forEach { functions.add(it) } + + functions.forEach { + it?.let { function -> + function.allOverriddenDescriptors + .map { OverriddenFunctionDescriptor(function, it) } + .filter { it.needBridge } + .filter { it.canBeCalledVirtually } + .distinctBy { it.bridgeDirections } + .forEach { buildBridge(it, irClass) + } + } + } } private object DECLARATION_ORIGIN_BRIDGE_METHOD : IrDeclarationOriginImpl("BRIDGE_METHOD") - private fun buildBridge(descriptor: FunctionDescriptor?, irClass: IrClass) { - if (descriptor == null) return - if (descriptor.bridgeDirections.allNotNeeded()) - return + private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) { + + println("BUILD_BRIDGE fun: ${descriptor.descriptor}") + println("BUILD_BRIDGE kind: ${descriptor.descriptor.kind}") + println("BUILD_BRIDGE target: ${descriptor.descriptor.target}") + println("BUILD_BRIDGE overridden: ${descriptor.overriddenDescriptor}") + println() val bridgeDescriptor = context.specialDescriptorsFactory.getBridgeDescriptor(descriptor) + val target = descriptor.descriptor.target - val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, descriptor.target, - superQualifier = descriptor.target.containingDeclaration as ClassDescriptor /* Call non-virtually */).apply { + val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target, + superQualifier = target.containingDeclaration as ClassDescriptor /* Call non-virtually */).apply { val dispatchReceiverParameter = bridgeDescriptor.dispatchReceiverParameter if (dispatchReceiverParameter != null) dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt index 5cf1eb82631..75127865b6c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt @@ -37,6 +37,8 @@ import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.utils.addToStdlib.singletonList import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList +// TODO: cross-module usage. + internal data class LoweredSyntheticFunction(val functionDescriptor: FunctionDescriptor, val containingClass: ClassDescriptor) internal data class LoweredEnumEntry(val implObject: ClassDescriptor, val valuesProperty: PropertyDescriptor,