Merge pull request #263 from JetBrains/class_delegation

Class delegation
This commit is contained in:
Igor Chevdar
2017-02-22 18:14:56 +05:00
committed by GitHub
20 changed files with 574 additions and 162 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,26 @@ 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(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): FunctionDescriptor {
val descriptor = overriddenFunctionDescriptor.descriptor.original
assert(overriddenFunctionDescriptor.needBridge,
{ "Function $descriptor is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor}" })
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
return bridgesDescriptors.getOrPut(descriptor to bridgeDirections) {
SimpleFunctionDescriptorImpl.create(
descriptor.containingDeclaration,
Annotations.EMPTY,
("<bridge-to>" + descriptor.functionName).synthesizedName,
("<bridge-" + bridgeDirections.toString() + ">" + descriptor.functionName).synthesizedName,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE).apply {
initializeBridgeDescriptor(this, descriptor)
initializeBridgeDescriptor(this, 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 +71,8 @@ internal class SpecialDescriptorsFactory(val context: Context) {
bridgeDescriptor.initialize(
extensionReceiverType,
descriptor.dispatchReceiverParameter,
// TODO: bug in descriptor - https://youtrack.jetbrains.com/issue/KT-16438.
(descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter,
descriptor.typeParameters,
descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
when (bridgeDirections[index + 2]) {
@@ -56,7 +56,9 @@ internal class KonanLower(val context: Context) {
VarargInjectionLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.BRIDGES_BUILDING) {
BridgesBuilding(context).lower(irFile)
DelegationLowering(context).runOnFilePostfix(irFile)
BridgesBuilding(context).runOnFilePostfix(irFile)
DirectBridgesCallsLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.AUTOBOX) {
Autoboxing(context).lower(irFile)
@@ -15,15 +15,38 @@ 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.target.needBridgeTo(overriddenDescriptor)
}
fun trivialOverride() = descriptor.original == overriddenDescriptor
val bridgeDirections: BridgeDirections
get() = descriptor.target.bridgeDirectionsTo(overriddenDescriptor)
val canBeCalledVirtually: Boolean
// 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) {
@@ -45,50 +68,39 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
if (overridingMethod == null) {
superMethod
} else {
if (!superMethod.trivialOverride())
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, superMethod.descriptor))
// Overriding method is defined in the current class and is not inherited - take it as is.
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, overridingMethod))
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, superMethod.descriptor))
OverriddenFunctionDescriptor(overridingMethod, superMethod.overriddenDescriptor)
}
}
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) }
// Add all possible (descriptor, overriddenDescriptor) edges for now, redundant will be removed later.
methods.mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it) }
val list = inheritedVtableSlots + newVtableSlots.filter { it.descriptor.isOverridable }.sortedBy {
it.overriddenDescriptor.functionName.localHash.value
}
list
val inheritedVtableSlotsSet = inheritedVtableSlots.map { it.descriptor to it.bridgeDirections }.toSet()
val filteredNewVtableSlots = newVtableSlots
.filterNot { inheritedVtableSlotsSet.contains(it.descriptor to it.bridgeDirections) }
.distinctBy { it.descriptor to it.bridgeDirections }
.filter { it.descriptor.isOverridable }
inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.functionName.localHash.value }
}
fun vtableIndex(function: FunctionDescriptor): Int {
val target = function.target
val index = vtableEntries.indexOfFirst { it.overriddenDescriptor == target }
val bridgeDirections = function.target.bridgeDirectionsTo(function.original)
val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections }
if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString())
return index
}
private val ClassDescriptor.contributedMethodsWithOverridden: List<OverriddenFunctionDescriptor>
get() {
return contributedMethods.flatMap { method ->
method.allOverriddenDescriptors.map { OverriddenFunctionDescriptor(method, it) }
}.distinctBy {
Triple(it.overriddenDescriptor.functionName, it.descriptor, it.needBridge)
}.sortedBy {
it.overriddenDescriptor.functionName.localHash.value
}
}
val methodTableEntries: List<OverriddenFunctionDescriptor> by lazy {
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 }
}
classDescriptor.contributedMethods
.flatMap { method -> method.allOverriddenDescriptors.map { OverriddenFunctionDescriptor(method, it) } }
.filter { it.canBeCalledVirtually }
.distinctBy { Triple(it.overriddenDescriptor.functionName, it.descriptor, it.needBridge) }
.sortedBy { it.overriddenDescriptor.functionName.localHash.value }
// TODO: probably method table should contain all accessible methods to improve binary compatibility
}
@@ -49,6 +49,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 +167,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 +211,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 +226,60 @@ 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
override fun toString(): String {
val result = StringBuilder()
array.forEach {
result.append(when (it) {
BridgeDirection.FROM_VALUE_TYPE -> 'U' // unbox
BridgeDirection.TO_VALUE_TYPE -> 'B' // box
BridgeDirection.NOT_NEEDED -> 'N' // none
})
}
return ourDirections
return result.toString()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is BridgeDirections) return false
return array.size == other.array.size
&& array.indices.all { array[it] == other.array[it] }
}
override fun hashCode(): Int {
var result = 0
array.forEach { result = result * 31 + it.ordinal }
return result
}
}
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)
val target = this.target
if (!kind.isReal
&& OverridingUtil.overrides(target, overriddenDescriptor)
&& ourDirections == target.bridgeDirectionsTo(overriddenDescriptor)) {
// Bridge is inherited from superclass.
return BridgeDirections(this.valueParameters.size)
}
return ourDirections
}
@@ -2,23 +2,25 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.backend.konan.KonanPhase
import org.jetbrains.kotlin.backend.konan.PhaseManager
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.IrInlineFunctionBody
import org.jetbrains.kotlin.backend.konan.ir.getArguments
import org.jetbrains.kotlin.backend.konan.ir.ir2string
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
import org.jetbrains.kotlin.ir.descriptors.IrImplementingDelegateDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrSetterCallImpl
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
@@ -1222,7 +1224,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private fun evaluateGetField(value: IrGetField): LLVMValueRef {
context.log("evaluateGetField : ${ir2string(value)}")
if (value.descriptor.dispatchReceiverParameter != null) {
if (value.descriptor.dispatchReceiverParameter != null
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|| value.descriptor is IrImplementingDelegateDescriptorImpl) {
val thisPtr = evaluateExpression(value.receiver!!)
return codegen.loadSlot(
fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar())
@@ -1251,7 +1255,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private fun evaluateSetField(value: IrSetField): LLVMValueRef {
context.log("evaluateSetField : ${ir2string(value)}")
val valueToAssign = evaluateExpression(value.value)
if (value.descriptor.dispatchReceiverParameter != null) {
if (value.descriptor.dispatchReceiverParameter != null
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|| value.descriptor is IrImplementingDelegateDescriptorImpl) {
val thisPtr = evaluateExpression(value.receiver!!)
codegen.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
}
@@ -7,6 +7,8 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrImplementingDelegateDescriptorImpl
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptorImpl
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName
@@ -296,8 +298,12 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val descriptor = declaration.descriptor
val dispatchReceiverParameter = descriptor.dispatchReceiverParameter
if (dispatchReceiverParameter != null) {
val containingClass = dispatchReceiverParameter.containingDeclaration
if (dispatchReceiverParameter != null
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|| descriptor is IrImplementingDelegateDescriptorImpl) {
val containingClass = dispatchReceiverParameter?.containingDeclaration
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
?: descriptor.containingDeclaration
val classDeclarations = this.classes[containingClass] ?: error(containingClass.toString())
val allFields = classDeclarations.fields
@@ -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
@@ -169,7 +170,13 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
get() {
val target = descriptor.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.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()) {
target // Bridge is inherited from superclass.
} else {
descriptor
}
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,171 @@
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.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. boxing/unboxing will be in the corresponding bridge.
return expression
}
irClass.descriptor.contributedMethods.forEach { functions.add(it) }
val target = descriptor.target
val needBridge = descriptor.original.needBridgeTo(target)
if (descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION && !needBridge)
return expression
functions.forEach { buildBridge(it, irClass) }
val toCall = if (needBridge) {
target
} else {
// Need to call delegating function.
context.specialDescriptorsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(descriptor, target))
}
return irClass
return IrCallImpl(expression.startOffset, expression.endOffset,
toCall, remapTypeArguments(expression, toCall)).apply {
dispatchReceiver = expression.dispatchReceiver
extensionReceiver = expression.extensionReceiver
mapValueParameters { expression.getValueArgument(it)!! }
}
}
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)!! }
)
}
})
}
}
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD")
internal class DelegationLowering(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
irClass.declarations.transformFlat {
when (it) {
is IrFunction -> {
val transformedFun = transformBridgeToDelegatedMethod(irClass, it)
if (transformedFun == null) null
else listOf(transformedFun)
}
is IrProperty -> {
val getter = transformBridgeToDelegatedMethod(irClass, it.getter)
val setter = transformBridgeToDelegatedMethod(irClass, it.setter)
if (getter != null) it.getter = getter
if (setter != null) it.setter = setter
null
}
else -> null
}
}
}
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD")
// TODO: hack because of broken IR for synthesized delegated members: https://youtrack.jetbrains.com/issue/KT-16486.
private fun transformBridgeToDelegatedMethod(irClass: IrClass, irFunction: IrFunction?): IrFunction? {
if (irFunction == null || irFunction.descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION) return null
private fun buildBridge(descriptor: FunctionDescriptor?, irClass: IrClass) {
if (descriptor == null) return
if (descriptor.bridgeDirections.allNotNeeded())
return
val body = irFunction.body as? IrBlockBody
?: throw AssertionError("Unexpected method body: ${irFunction.body}")
val statement = body.statements.single()
val delegatedCall = ((statement as? IrReturn)?.value ?: statement) as? IrCall
?: throw AssertionError("Unexpected method body: $statement")
val propertyGetter = delegatedCall.dispatchReceiver as? IrGetValue
?: throw AssertionError("Unexpected dispatch receiver: ${delegatedCall.dispatchReceiver}")
val propertyDescriptor = propertyGetter.descriptor as? PropertyDescriptor
?: throw AssertionError("Unexpected dispatch receiver descriptor: ${propertyGetter.descriptor}")
val delegated = context.specialDescriptorsFactory.getBridgeDescriptor(
OverriddenFunctionDescriptor(irFunction.descriptor, delegatedCall.descriptor as FunctionDescriptor))
val newFunction = IrFunctionImpl(irFunction.startOffset, irFunction.endOffset, DECLARATION_ORIGIN_BRIDGE_METHOD, delegated)
val irBlockBody = IrBlockBodyImpl(irFunction.startOffset, irFunction.endOffset)
val returnType = delegatedCall.descriptor.returnType!!
val irCall = IrCallImpl(irFunction.startOffset, irFunction.endOffset, returnType, delegatedCall.descriptor, null)
val receiver = IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, irClass.descriptor.thisAsReceiverParameter)
irCall.dispatchReceiver = IrGetFieldImpl(irFunction.startOffset, irFunction.endOffset, propertyDescriptor, receiver)
irCall.extensionReceiver = delegated.extensionReceiverParameter?.let { extensionReceiver ->
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, extensionReceiver)
}
irCall.mapValueParameters { overriddenValueParameter ->
val delegatedValueParameter = delegated.valueParameters[overriddenValueParameter.index]
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, delegatedValueParameter)
}
if (KotlinBuiltIns.isUnit(returnType) || KotlinBuiltIns.isNothing(returnType)) {
irBlockBody.statements.add(irCall)
} else {
val irReturn = IrReturnImpl(irFunction.startOffset, irFunction.endOffset, context.builtIns.nothingType, delegated, irCall)
irBlockBody.statements.add(irReturn)
}
newFunction.body = irBlockBody
return newFunction
}
}
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.bridgeDirections.allNotNeeded() }
.filter { it.canBeCalledVirtually }
.distinctBy { it.bridgeDirections }
.forEach {
buildBridge(it, irClass)
}
}
}
}
private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
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,6 +2,7 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
@@ -37,6 +38,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,
@@ -173,7 +176,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructorDescriptor)
}
val memberScope = MemberScope.Empty
val memberScope = SimpleMemberScope(irClass.descriptor.unsubstitutedMemberScope.getContributedDescriptors().toList())
defaultClassDescriptor.initialize(memberScope, constructors, null)
return defaultClass
+50 -1
View File
@@ -36,7 +36,11 @@ task clean {
}
task run() {
dependsOn(tasks.withType(KonanTest).matching { !(it instanceof RunExternalTestGroup) && it.enabled })
String prefix = project.findProperty("prefix")
if (prefix != null)
dependsOn(tasks.withType(KonanTest).matching { !(it instanceof RunExternalTestGroup) && it.enabled && it.name.startsWith(prefix) })
else
dependsOn(tasks.withType(KonanTest).matching { !(it instanceof RunExternalTestGroup) && it.enabled })
}
task run_external () {
@@ -362,6 +366,16 @@ task enum_companionObject(type: RunKonanTest) {
source = "codegen/enum/companionObject.kt"
}
task enum_interfaceCallNoEntryClass(type: RunKonanTest) {
goldValue = "('z3', 3)\n('z3', 3)\n"
source = "codegen/enum/interfaceCallNoEntryClass.kt"
}
task enum_interfaceCallWithEntryClass(type: RunKonanTest) {
goldValue = "z1z2\nz1z2\n"
source = "codegen/enum/interfaceCallWithEntryClass.kt"
}
task innerClass_simple(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/innerClass/simple.kt"
@@ -537,6 +551,41 @@ task bridges_test13(type: RunKonanTest) {
source = "codegen/bridges/test13.kt"
}
task bridges_test14(type: RunKonanTest) {
goldValue = "42\n56\n42\n56\n56\n42\n156\n142\n"
source = "codegen/bridges/test14.kt"
}
task bridges_test15(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/bridges/test15.kt"
}
task bridges_test16(type: RunKonanTest) {
goldValue = "OK\nOK\n"
source = "codegen/bridges/test16.kt"
}
task classDelegation_method(type: RunKonanTest) {
goldValue = "OKOK\n"
source = "codegen/classDelegation/method.kt"
}
task classDelegation_property(type: RunKonanTest) {
goldValue = "4242\n"
source = "codegen/classDelegation/property.kt"
}
task classDelegation_generic(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/classDelegation/generic.kt"
}
task classDelegation_withBridge(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/classDelegation/withBridge.kt"
}
task array0(type: RunKonanTest) {
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
source = "runtime/collections/array0.kt"
@@ -0,0 +1,44 @@
open class A<T, U> {
open fun foo(x: T, y: U) {
println(x.toString())
println(y.toString())
}
}
interface I1<T> {
fun foo(x: Int, y: T)
}
interface I2<T> {
fun foo(x: T, y: Int)
}
class B : A<Int, Int>(), I1<Int>, I2<Int> {
var z: Int = 5
var q: Int = 7
override fun foo(x: Int, y: Int) {
z = x
q = y
}
}
fun zzz(a: A<Int, Int>) {
a.foo(42, 56)
}
fun main(args: Array<String>) {
val b = B()
zzz(b)
val a = A<Int, Int>()
zzz(a)
println(b.z)
println(b.q)
val i1: I1<Int> = b
i1.foo(56, 42)
println(b.z)
println(b.q)
val i2: I2<Int> = b
i2.foo(156, 142)
println(b.z)
println(b.q)
}
@@ -0,0 +1,35 @@
// non-generic interface, generic impl, vtable call + interface call
open class A<T> {
open var size: T = 56 as T
}
interface C {
var size: Int
}
open class B : C, A<Int>()
open class D: B() {
override var size: Int = 117
}
fun <T> foo(a: A<T>) {
a.size = 42 as T
}
fun box(): String {
val b = B()
foo(b)
if (b.size != 42) return "fail 1"
val d = D()
if (d.size != 117) return "fail 2"
foo(d)
if (d.size != 42) return "fail 3"
return "OK"
}
fun main(args: Array<String>) {
println(box())
}
@@ -0,0 +1,20 @@
interface A {
fun foo(): String
}
abstract class C: A
open class B: C() {
override fun foo(): String {
return "OK"
}
}
fun bar(c: C) = c.foo()
fun main(args: Array<String>) {
val b = B()
val c: C = b
println(bar(b))
println(bar(c))
}
@@ -0,0 +1,21 @@
open class Content() {
override fun toString() = "OK"
}
interface Box<E> {
fun get(): E
}
interface ContentBox<T : Content> : Box<T>
object Impl : ContentBox<Content> {
override fun get(): Content = Content()
}
class ContentBoxDelegate<T : Content>() : ContentBox<T> by (Impl as ContentBox<T>)
fun box() = ContentBoxDelegate<Content>().get().toString()
fun main(args: Array<String>) {
println(box())
}
@@ -0,0 +1,19 @@
interface A<T> {
fun foo(): T
}
class B : A<String> {
override fun foo() = "OK"
}
class C(a: A<String>) : A<String> by a
fun box(): String {
val c = C(B())
val a: A<String> = c
return c.foo() + a.foo()
}
fun main(args: Array<String>) {
println(box())
}
@@ -0,0 +1,19 @@
interface A {
val x: Int
}
class C: A {
override val x: Int = 42
}
class Q(a: A): A by a
fun box(): String {
val q = Q(C())
val a: A = q
return q.x.toString() + a.x.toString()
}
fun main(args: Array<String>) {
println(box())
}
@@ -0,0 +1,28 @@
interface A<T> {
fun foo(t: T): String
}
interface B {
fun foo(t: Int) = "B"
}
class Z : B
class Z1 : A<Int>, B by Z()
fun box(): String {
val z1 = Z1()
val z1a: A<Int> = z1
val z1b: B = z1
return when {
z1.foo( 0) != "B" -> "Fail #1"
z1a.foo( 0) != "B" -> "Fail #2"
z1b.foo( 0) != "B" -> "Fail #3"
else -> "OK"
}
}
fun main(args: Array<String>) {
println(box())
}
@@ -0,0 +1,19 @@
interface A {
fun foo(): String
}
enum class Zzz(val zzz: String, val x: Int) : A {
Z1("z1", 1),
Z2("z2", 2),
Z3("z3", 3);
override fun foo(): String{
return "('$zzz', $x)"
}
}
fun main(args: Array<String>) {
println(Zzz.Z3.foo())
val a: A = Zzz.Z3
println(a.foo())
}
@@ -0,0 +1,22 @@
interface A {
fun f(): String
}
enum class Zzz: A {
Z1 {
override fun f() = "z1"
},
Z2 {
override fun f() = "z2"
};
override fun f() = ""
}
fun main(args: Array<String>) {
println(Zzz.Z1.f() + Zzz.Z2.f())
val a1: A = Zzz.Z1
val a2: A = Zzz.Z2
println(a1.f() + a2.f())
}