diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index c918bb99ca4..cb57f181512 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -37,18 +37,19 @@ internal class SpecialDescriptorsFactory(val context: Context) { false, false, false, false, false, false).initialize(outerClassDescriptor.defaultType, dispatchReceiverParameter = receiver) } - 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) { + 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.descriptor.containingDeclaration, + descriptor.containingDeclaration, Annotations.EMPTY, - ("" + descriptor.descriptor.functionName).synthesizedName, + ("" + descriptor.functionName).synthesizedName, CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE).apply { - initializeBridgeDescriptor(this, descriptor.descriptor, bridgeDirections.array) + initializeBridgeDescriptor(this, descriptor, bridgeDirections.array) } } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 9687b91b2fd..a1207cc1e92 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -55,8 +55,14 @@ internal class KonanLower(val context: Context) { phaser.phase(KonanPhase.LOWER_VARARG) { VarargInjectionLowering(context).runOnFilePostfix(irFile) } + phaser.phase(KonanPhase.LOWER_DELEGATION) { + DelegationLowering(context).runOnFilePostfix(irFile) + } phaser.phase(KonanPhase.BRIDGES_BUILDING) { - BridgesBuilding(context).lower(irFile) + BridgesBuilding(context).runOnFilePostfix(irFile) + } + phaser.phase(KonanPhase.LOWER_DIRECT_BRIDGES_CALLS) { + DirectBridgesCallsLowering(context).runOnFilePostfix(irFile) } phaser.phase(KonanPhase.AUTOBOX) { Autoboxing(context).lower(irFile) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index fc226819486..a3eff6163b1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -25,6 +25,8 @@ enum class KonanPhase(val description: String, /* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"), /* ... ... */ LOWER_INITIALIZERS("Initializers lowering"), /* ... ... */ BRIDGES_BUILDING("Bridges building"), + /* ... ... */ LOWER_DELEGATION("Delegation lowering"), + /* ... ... */ LOWER_DIRECT_BRIDGES_CALLS("Direct bridges calls lowering"), /* ... */ BITCODE("LLVM BitCode Generation"), /* ... ... */ RTTI("RTTI Generation"), /* ... ... */ CODEGEN("Code Generation"), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt index f86c26ed993..b64e06e500c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt @@ -16,22 +16,16 @@ internal class OverriddenFunctionDescriptor(val descriptor: FunctionDescriptor, get() { if (descriptor.modality == Modality.ABSTRACT) return false 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) - } + get() = descriptor.target.bridgeDirectionsTo(overriddenDescriptor) - val canBeCalledVirtually + 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 } + get() = overriddenDescriptor.isOverridable + || DescriptorUtils.getAllOverriddenDeclarations(overriddenDescriptor).any { it.isOverridable } override fun toString(): String { @@ -76,9 +70,8 @@ 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. + // Add all possible (descriptor, overriddenDescriptor) edges for now, redundant will be removed later. + newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, superMethod.descriptor)) newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, overridingMethod)) OverriddenFunctionDescriptor(overridingMethod, superMethod.overriddenDescriptor) } @@ -94,15 +87,13 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con } println() - // TODO: why put all pairs ? val zzz = inheritedVtableSlots.map { it.descriptor to it.bridgeDirections }.toSet() - methods// Find newly defined methods. - // TODO: Select target because method might be taken from default implementation of interface. - .mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it) } + methods.mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it) } + val filteredNewVtableSlots = newVtableSlots - .filter { (it.descriptor.kind.isReal || it.needBridge) && !zzz.contains(it.descriptor to it.bridgeDirections) } + .filter { !zzz.contains(it.descriptor to it.bridgeDirections) } .distinctBy { it.descriptor to it.bridgeDirections } .filter { it.descriptor.isOverridable } println("VTABLE_ENTRIES new vtable:") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt index 1baed157f66..9a666332096 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt @@ -17,7 +17,6 @@ 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.resolve.DescriptorUtils import org.jetbrains.kotlin.types.KotlinType internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPass { @@ -33,11 +32,14 @@ internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPa } val target = descriptor.target - if (descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION && !descriptor.original.needBridgeTo(target)) + val needBridge = descriptor.original.needBridgeTo(target) + if (descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION && !needBridge) return expression + val toCall = if (needBridge) target else context.specialDescriptorsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(descriptor, target)) + return IrCallImpl(expression.startOffset, expression.endOffset, - target, remapTypeArguments(expression, target)).apply { + toCall, remapTypeArguments(expression, toCall)).apply { dispatchReceiver = expression.dispatchReceiver extensionReceiver = expression.extensionReceiver mapValueParameters { expression.getValueArgument(it)!! } @@ -59,6 +61,73 @@ internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPa } } +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 || setter != null) { + it.getter = getter + it.setter = setter + } + null + } + else -> null + } + } + } + + // TODO: hack because of broken IR for synthesized delegated members. + private fun transformBridgeToDelegatedMethod(irClass: IrClass, irFunction: IrFunction?): IrFunction? { + if (irFunction == null || irFunction.descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION) return null + + 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() @@ -78,7 +147,7 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass { it?.let { function -> function.allOverriddenDescriptors .map { OverriddenFunctionDescriptor(function, it) } - .filter { it.needBridge } + .filter { !it.bridgeDirections.allNotNeeded() } .filter { it.canBeCalledVirtually } .distinctBy { it.bridgeDirections } .forEach { buildBridge(it, irClass) @@ -87,9 +156,6 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass { } } - private object DECLARATION_ORIGIN_BRIDGE_METHOD : - IrDeclarationOriginImpl("BRIDGE_METHOD") - private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) { println("BUILD_BRIDGE fun: ${descriptor.descriptor}")