Rewrote vtable building taking into account possibility of multiple bridges for a single method

This commit is contained in:
Igor Chevdar
2017-02-21 14:42:16 +03:00
parent ab0f8cb6cd
commit 7fa44ebc0d
7 changed files with 265 additions and 136 deletions
@@ -5,7 +5,10 @@ import llvm.LLVMModuleRef
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.Ir 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.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
@@ -20,7 +23,7 @@ import java.lang.System.out
internal class SpecialDescriptorsFactory(val context: Context) { internal class SpecialDescriptorsFactory(val context: Context) {
private val outerThisDescriptors = mutableMapOf<ClassDescriptor, PropertyDescriptor>() private val outerThisDescriptors = mutableMapOf<ClassDescriptor, PropertyDescriptor>()
private val bridgesDescriptors = mutableMapOf<FunctionDescriptor, FunctionDescriptor>() private val bridgesDescriptors = mutableMapOf<Pair<FunctionDescriptor, BridgeDirections>, FunctionDescriptor>()
fun getOuterThisFieldDescriptor(innerClassDescriptor: ClassDescriptor): PropertyDescriptor = fun getOuterThisFieldDescriptor(innerClassDescriptor: ClassDescriptor): PropertyDescriptor =
if (!innerClassDescriptor.isInner) throw AssertionError("Class is not inner: $innerClassDescriptor") 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) false, false, false, false, false, false).initialize(outerClassDescriptor.defaultType, dispatchReceiverParameter = receiver)
} }
fun getBridgeDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor { fun getBridgeDescriptor(descriptor: OverriddenFunctionDescriptor): FunctionDescriptor {
return bridgesDescriptors.getOrPut(descriptor) { 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( SimpleFunctionDescriptorImpl.create(
descriptor.containingDeclaration, descriptor.descriptor.containingDeclaration,
Annotations.EMPTY, Annotations.EMPTY,
("<bridge-to>" + descriptor.functionName).synthesizedName, ("<bridge-" + bridgeDirections.toString() + ">" + descriptor.descriptor.functionName).synthesizedName,
CallableMemberDescriptor.Kind.DECLARATION, CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE).apply { SourceElement.NO_SOURCE).apply {
initializeBridgeDescriptor(this, descriptor) initializeBridgeDescriptor(this, descriptor.descriptor, bridgeDirections.array)
} }
} }
} }
private fun initializeBridgeDescriptor(bridgeDescriptor: SimpleFunctionDescriptorImpl, descriptor: FunctionDescriptor) { private fun initializeBridgeDescriptor(bridgeDescriptor: SimpleFunctionDescriptorImpl,
val bridgeDirections = descriptor.bridgeDirections descriptor: FunctionDescriptor,
if (bridgeDirections.allNotNeeded()) bridgeDirections: Array<BridgeDirection>) {
throw AssertionError("Function $descriptor is not needed in a bridge")
val returnType = when (bridgeDirections[0]) { val returnType = when (bridgeDirections[0]) {
BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!! BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!!
BridgeDirection.NOT_NEEDED -> descriptor.returnType BridgeDirection.NOT_NEEDED -> descriptor.returnType
@@ -66,7 +70,7 @@ internal class SpecialDescriptorsFactory(val context: Context) {
bridgeDescriptor.initialize( bridgeDescriptor.initialize(
extensionReceiverType, extensionReceiverType,
descriptor.dispatchReceiverParameter, (descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter,
descriptor.typeParameters, descriptor.typeParameters,
descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor -> descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
when (bridgeDirections[index + 2]) { when (bridgeDirections[index + 2]) {
@@ -15,19 +15,50 @@ internal class OverriddenFunctionDescriptor(val descriptor: FunctionDescriptor,
val needBridge: Boolean val needBridge: Boolean
get() { get() {
if (descriptor.modality == Modality.ABSTRACT) return false if (descriptor.modality == Modality.ABSTRACT) return false
return descriptor.needBridgeTo(overriddenDescriptor) return descriptor.kind == CallableMemberDescriptor.Kind.DELEGATION
//|| descriptor.needBridgeTo(overriddenDescriptor)
|| descriptor.target.needBridgeTo(overriddenDescriptor) || descriptor.target.needBridgeTo(overriddenDescriptor)
} }
fun trivialOverride() = descriptor.original == 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 { override fun toString(): String {
return "(descriptor=$descriptor, overriddenDescriptor=$overriddenDescriptor)" 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) { internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val context: Context) {
val vtableEntries: List<OverriddenFunctionDescriptor> by lazy { val vtableEntries: List<OverriddenFunctionDescriptor> /*by lazy*/ get() {
println("VTABLE_ENTRIES class: $classDescriptor")
assert(!classDescriptor.isInterface) 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. println("VTABLE_ENTRIES inherited vtable:")
// Select target because method might be taken from default implementation of interface. inheritedVtableSlots.forEach {
.mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it.target) } 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 { // TODO: why put all pairs <descriptor, overriddenDescriptor>?
it.overriddenDescriptor.functionName.localHash.value 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 { fun vtableIndex(function: FunctionDescriptor): Int {
val target = function.target 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()) 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<OverriddenFunctionDescriptor> private val ClassDescriptor.contributedMethodsWithOverridden: List<OverriddenFunctionDescriptor>
@@ -81,14 +155,26 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
} }
} }
val methodTableEntries: List<OverriddenFunctionDescriptor> by lazy { val methodTableEntries: List<OverriddenFunctionDescriptor> /*by lazy*/ get() {
assert(!classDescriptor.isAbstract()) assert(!classDescriptor.isAbstract())
classDescriptor.contributedMethodsWithOverridden.filter { println("METHOD_TABLE_ENTRIES: class = $this")
// We check that either method is open, or one of declarations it overrides
// is open. val contributedMethodsWithOverridden = classDescriptor.contributedMethodsWithOverridden
it.overriddenDescriptor.isOverridable || DescriptorUtils.getAllOverriddenDeclarations(it.overriddenDescriptor).any { it.isOverridable } 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 // TODO: probably method table should contain all accessible methods to improve binary compatibility
} }
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
/** /**
* List of all implemented interfaces (including those which implemented by a super class) * List of all implemented interfaces (including those which implemented by a super class)
@@ -49,6 +50,7 @@ internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T {
val overridden = OverridingUtil.getOverriddenDeclarations(this) val overridden = OverridingUtil.getOverriddenDeclarations(this)
val filtered = OverridingUtil.filterOutOverridden(overridden) val filtered = OverridingUtil.filterOutOverridden(overridden)
// TODO: is it correct to take first? // TODO: is it correct to take first?
@Suppress("UNCHECKED_CAST")
return filtered.first { it.modality != Modality.ABSTRACT } as T return filtered.first { it.modality != Modality.ABSTRACT } as T
} }
} }
@@ -166,6 +168,7 @@ internal val <T : CallableMemberDescriptor> T.allOverriddenDescriptors: List<T>
val result = mutableListOf<T>() val result = mutableListOf<T>()
fun traverse(descriptor: T) { fun traverse(descriptor: T) {
result.add(descriptor) result.add(descriptor)
@Suppress("UNCHECKED_CAST")
descriptor.overriddenDescriptors.forEach { traverse(it as T) } descriptor.overriddenDescriptors.forEach { traverse(it as T) }
} }
traverse(this) 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) private fun FunctionDescriptor.needBridgeToAt(target: FunctionDescriptor, index: Int)
= hasValueTypeAt(index) xor target.hasValueTypeAt(index) = hasValueTypeAt(index) xor target.hasValueTypeAt(index)
@@ -230,39 +227,52 @@ internal enum class BridgeDirection {
TO_VALUE_TYPE TO_VALUE_TYPE
} }
private fun FunctionDescriptor.bridgeDirectionAt(index: Int) : BridgeDirection { private fun FunctionDescriptor.bridgeDirectionToAt(target: FunctionDescriptor, index: Int): BridgeDirection {
if (kind.isReal) { when {
if (hasValueTypeAt(index) && overridesFunWithReferenceAt(index)) hasValueTypeAt(index) && target.hasReferenceAt(index) -> return BridgeDirection.FROM_VALUE_TYPE
return BridgeDirection.FROM_VALUE_TYPE hasReferenceAt(index) && target.hasValueTypeAt(index) -> return BridgeDirection.TO_VALUE_TYPE
return BridgeDirection.NOT_NEEDED else -> 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 bridgesEqual(first: Array<BridgeDirection>, second: Array<BridgeDirection>) internal class BridgeDirections(val array: Array<BridgeDirection>) {
= first.indices.none { first[it] != second[it] } constructor(parametersCount: Int): this(Array<BridgeDirection>(parametersCount + 2, { BridgeDirection.NOT_NEEDED }))
internal fun Array<BridgeDirection>.allNotNeeded() = this.all { it == BridgeDirection.NOT_NEEDED } fun allNotNeeded(): Boolean = array.all { it == BridgeDirection.NOT_NEEDED }
internal val FunctionDescriptor.bridgeDirections: Array<BridgeDirection> override fun toString(): String {
get() { return String(array.map {
val ourDirections = Array<BridgeDirection>(this.valueParameters.size + 2, { BridgeDirection.NOT_NEEDED }) when (it) {
if (modality == Modality.ABSTRACT) BridgeDirection.FROM_VALUE_TYPE -> 'U' // unbox
return ourDirections BridgeDirection.TO_VALUE_TYPE -> 'B' // box
for (index in ourDirections.indices) BridgeDirection.NOT_NEEDED -> 'N' // none
ourDirections[index] = this.bridgeDirectionAt(index) }
}.toCharArray())
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 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
}
@@ -6,6 +6,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny 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", val fieldsPtr = staticData.placeGlobalConstArray("kfields:$className",
runtime.fieldTableRecordType, fields) runtime.fieldTableRecordType, fields)
println("GEN_TABLES: class = $classDesc")
val methods = if (classDesc.isAbstract()) { val methods = if (classDesc.isAbstract()) {
emptyList() emptyList()
} else { } 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") throw AssertionError("Duplicate method table entry: functionName = '$functionName', hash = '${nameSignature.value}', entry1 = $previous, entry2 = $it")
// TODO: compile-time resolution limits binary compatibility // 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) MethodTableRecord(nameSignature, methodEntryPoint)
}.sortedBy { it.nameSignature.value } }.sortedBy { it.nameSignature.value }
} }
@@ -154,7 +159,11 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
typeInfo typeInfo
} else { } else {
// TODO: compile-time resolution limits binary compatibility // 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) val vtable = ConstArray(int8TypePtr, vtableEntries)
Struct(typeInfo, vtable) Struct(typeInfo, vtable)
} }
@@ -167,9 +176,14 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
internal val OverriddenFunctionDescriptor.implementation: FunctionDescriptor internal val OverriddenFunctionDescriptor.implementation: FunctionDescriptor
get() { get() {
println("IMPLEMENTATION fun: ${descriptor}")
println("IMPLEMENTATION overridden: ${overriddenDescriptor}")
val target = descriptor.target val target = descriptor.target
println("IMPLEMENTATION target: ${target}")
if (!needBridge) return target if (!needBridge) return target
val bridgeOwner = if (descriptor.bridgeDirections.allNotNeeded()) target else descriptor //val bridgeOwner = if (!descriptor.kind.isReal && OverridingUtil.overrides(target, overriddenDescriptor) && !descriptor.needBridgeTo(overriddenDescriptor)) if (descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()) target else descriptor
return context.specialDescriptorsFactory.getBridgeDescriptor(bridgeOwner) 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))
} }
} }
@@ -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<TypeParameterDescriptor, KotlinType>? {
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, * @return the [ValueType] given type represented in generated code as,
* or `null` if represented as object reference. * or `null` if represented as object reference.
@@ -1,63 +1,108 @@
package org.jetbrains.kotlin.backend.konan.lower 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.Context
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrStatement
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.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.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
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
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 { internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irBody: IrBody) {
irFile.transformChildrenVoid(object : IrElementTransformerVoid() { irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
override fun visitClass(declaration: IrClass): IrStatement { expression.transformChildrenVoid(this)
val irClass = super.visitClass(declaration) as IrClass val descriptor = expression.descriptor as? FunctionDescriptor ?: return expression
if (descriptor.modality == Modality.ABSTRACT
val functions = mutableSetOf<FunctionDescriptor?>() || (expression.superQualifier == null && descriptor.isOverridable)) {
irClass.declarations.forEach { // A virtual call. box/unbox will be in the corresponding bridge.
when (it) { return expression
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) } 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<TypeParameterDescriptor, KotlinType>? {
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<FunctionDescriptor?>()
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 : private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD") IrDeclarationOriginImpl("BRIDGE_METHOD")
private fun buildBridge(descriptor: FunctionDescriptor?, irClass: IrClass) { private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
if (descriptor == null) return
if (descriptor.bridgeDirections.allNotNeeded()) println("BUILD_BRIDGE fun: ${descriptor.descriptor}")
return 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 bridgeDescriptor = context.specialDescriptorsFactory.getBridgeDescriptor(descriptor)
val target = descriptor.descriptor.target
val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, descriptor.target, val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target,
superQualifier = descriptor.target.containingDeclaration as ClassDescriptor /* Call non-virtually */).apply { superQualifier = target.containingDeclaration as ClassDescriptor /* Call non-virtually */).apply {
val dispatchReceiverParameter = bridgeDescriptor.dispatchReceiverParameter val dispatchReceiverParameter = bridgeDescriptor.dispatchReceiverParameter
if (dispatchReceiverParameter != null) if (dispatchReceiverParameter != null)
dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter) dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter)
@@ -37,6 +37,8 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.utils.addToStdlib.singletonList import org.jetbrains.kotlin.utils.addToStdlib.singletonList
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
// TODO: cross-module usage.
internal data class LoweredSyntheticFunction(val functionDescriptor: FunctionDescriptor, val containingClass: ClassDescriptor) internal data class LoweredSyntheticFunction(val functionDescriptor: FunctionDescriptor, val containingClass: ClassDescriptor)
internal data class LoweredEnumEntry(val implObject: ClassDescriptor, val valuesProperty: PropertyDescriptor, internal data class LoweredEnumEntry(val implObject: ClassDescriptor, val valuesProperty: PropertyDescriptor,