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.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<ClassDescriptor, PropertyDescriptor>()
private val bridgesDescriptors = mutableMapOf<FunctionDescriptor, FunctionDescriptor>()
private val bridgesDescriptors = mutableMapOf<Pair<FunctionDescriptor, BridgeDirections>, 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,
("<bridge-to>" + descriptor.functionName).synthesizedName,
("<bridge-" + bridgeDirections.toString() + ">" + 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<BridgeDirection>) {
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]) {
@@ -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<OverriddenFunctionDescriptor> by lazy {
val vtableEntries: List<OverriddenFunctionDescriptor> /*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 <descriptor, overriddenDescriptor>?
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<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())
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
}
@@ -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 : CallableMemberDescriptor> 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 : CallableMemberDescriptor> T.allOverriddenDescriptors: List<T>
val result = mutableListOf<T>()
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<BridgeDirection>, second: Array<BridgeDirection>)
= first.indices.none { first[it] != second[it] }
internal class BridgeDirections(val array: Array<BridgeDirection>) {
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>
get() {
val ourDirections = Array<BridgeDirection>(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
}
@@ -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))
}
}
@@ -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,
* or `null` if represented as object reference.
@@ -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<FunctionDescriptor?>()
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<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 :
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)
@@ -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,