Rewrote vtable building taking into account possibility of multiple bridges for a single method
This commit is contained in:
+17
-13
@@ -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]) {
|
||||
|
||||
+102
-16
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+46
-36
@@ -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
|
||||
}
|
||||
+18
-4
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
-32
@@ -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.
|
||||
|
||||
+80
-35
@@ -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)
|
||||
|
||||
+2
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user