[K/N] Fix ObjCExport of coroutines for new lowerings

This commit is contained in:
Pavel Kunyavskiy
2022-09-07 11:04:01 +02:00
committed by Space Team
parent 7e89d59b59
commit 132bb941e1
2 changed files with 39 additions and 22 deletions
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.konan.llvm.objcexport
import kotlinx.cinterop.toCValues import kotlinx.cinterop.toCValues
import kotlinx.cinterop.toKString import kotlinx.cinterop.toKString
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
import org.jetbrains.kotlin.backend.konan.descriptors.OverriddenFunctionInfo import org.jetbrains.kotlin.backend.konan.descriptors.OverriddenFunctionInfo
@@ -27,9 +28,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrClassReference
import org.jetbrains.kotlin.ir.expressions.IrVararg import org.jetbrains.kotlin.ir.expressions.IrVararg
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.types.isUnit
@@ -303,6 +302,18 @@ internal class ObjCExportCodeGenerator(
val mapper: ObjCExportMapper val mapper: ObjCExportMapper
) : ObjCExportCodeGeneratorBase(codegen) { ) : ObjCExportCodeGeneratorBase(codegen) {
inline fun <reified T: IrFunction> T.getLowered(): T = when (this) {
is IrSimpleFunction -> when {
isSuspend -> this.getOrCreateFunctionWithContinuationStub(context) as T
else -> this
}
else -> this
}
val ObjCMethodSpec.BaseMethod<IrFunctionSymbol>.owner get() = symbol.owner.getLowered()
val ObjCMethodSpec.BaseMethod<IrConstructorSymbol>.owner get() = symbol.owner.getLowered()
val ObjCMethodSpec.BaseMethod<IrSimpleFunctionSymbol>.owner get() = symbol.owner.getLowered()
val selectorsToDefine = mutableMapOf<String, MethodBridge>() val selectorsToDefine = mutableMapOf<String, MethodBridge>()
val externalGlobalInitializers = mutableMapOf<LLVMValueRef, ConstValue>() val externalGlobalInitializers = mutableMapOf<LLVMValueRef, ConstValue>()
@@ -1178,13 +1189,13 @@ private fun ObjCExportCodeGenerator.generateTypeInfoArray(types: Set<IrClass>):
codegen.staticData.placeGlobalConstArray("", codegen.kTypeInfoPtr, typeInfos) codegen.staticData.placeGlobalConstArray("", codegen.kTypeInfoPtr, typeInfos)
} }
private fun effectiveThrowsClasses(method: IrFunction, symbols: KonanSymbols): List<IrClass> { private fun ObjCExportCodeGenerator.effectiveThrowsClasses(method: IrFunction, symbols: KonanSymbols): List<IrClass> {
if (method is IrSimpleFunction && method.overriddenSymbols.isNotEmpty()) { if (method is IrSimpleFunction && method.overriddenSymbols.isNotEmpty()) {
return effectiveThrowsClasses(method.overriddenSymbols.first().owner, symbols) return effectiveThrowsClasses(method.overriddenSymbols.first().owner, symbols)
} }
val throwsAnnotation = method.annotations.findAnnotation(KonanFqNames.throws) val throwsAnnotation = method.annotations.findAnnotation(KonanFqNames.throws)
?: return if (method.isSuspend) { ?: return if (method is IrSimpleFunction && method.origin == IrDeclarationOrigin.LOWERED_SUSPEND_FUNCTION) {
listOf(symbols.cancellationException.owner) listOf(symbols.cancellationException.owner)
} else { } else {
// Note: frontend ensures that all topmost overridden methods have (equal) @Throws annotations. // Note: frontend ensures that all topmost overridden methods have (equal) @Throws annotations.
@@ -1223,7 +1234,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
irFunction: IrFunction, irFunction: IrFunction,
baseMethod: ObjCMethodSpec.BaseMethod<IrSimpleFunctionSymbol> baseMethod: ObjCMethodSpec.BaseMethod<IrSimpleFunctionSymbol>
): ConstPointer { ): ConstPointer {
val baseIrFunction = baseMethod.symbol.owner val baseIrFunction = baseMethod.owner
val methodBridge = baseMethod.bridge val methodBridge = baseMethod.bridge
@@ -1288,7 +1299,14 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
} }
is MethodBridgeValueParameter.SuspendCompletion -> { is MethodBridgeValueParameter.SuspendCompletion -> {
val continuation = param(irFunction.allParametersCount) // The last argument. require(!irFunction.isSuspend) { "Suspend function should be lowered out at this point" }
parameter!!
val continuation = convertKotlin(
{ parameters[parameter]!! },
actualType = parameter.type,
expectedType = parameterToBase[parameter]!!.type,
resultLifetime = Lifetime.ARGUMENT
)
// TODO: consider placing interception into the converter to reduce code size. // TODO: consider placing interception into the converter to reduce code size.
val intercepted = callFromBridge( val intercepted = callFromBridge(
context.ir.symbols.objCExportInterceptedContinuation.owner.llvmFunction, context.ir.symbols.objCExportInterceptedContinuation.owner.llvmFunction,
@@ -1407,8 +1425,6 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
val actualReturnType = irFunction.returnType val actualReturnType = irFunction.returnType
val retVal = when { val retVal = when {
baseIrFunction.isSuspend -> genKotlinBaseMethodResult(Lifetime.RETURN_VALUE, methodBridge.returnBridge)
actualReturnType.isUnit() || actualReturnType.isNothing() -> { actualReturnType.isUnit() || actualReturnType.isNothing() -> {
genKotlinBaseMethodResult(Lifetime.ARGUMENT, methodBridge.returnBridge) genKotlinBaseMethodResult(Lifetime.ARGUMENT, methodBridge.returnBridge)
null null
@@ -1525,7 +1541,7 @@ private fun ObjCExportCodeGenerator.createMethodVirtualAdapter(
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter { ): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
val selector = baseMethod.selector val selector = baseMethod.selector
val methodBridge = baseMethod.bridge val methodBridge = baseMethod.bridge
val irFunction = baseMethod.symbol.owner val irFunction = baseMethod.owner
val imp = generateObjCImp(irFunction, irFunction, methodBridge, isVirtual = true) val imp = generateObjCImp(irFunction, irFunction, methodBridge, isVirtual = true)
return objCToKotlinMethodAdapter(selector, methodBridge, imp) return objCToKotlinMethodAdapter(selector, methodBridge, imp)
@@ -1539,7 +1555,7 @@ private fun ObjCExportCodeGenerator.createMethodAdapter(
private fun ObjCExportCodeGenerator.createFinalMethodAdapter( private fun ObjCExportCodeGenerator.createFinalMethodAdapter(
baseMethod: ObjCMethodSpec.BaseMethod<IrSimpleFunctionSymbol> baseMethod: ObjCMethodSpec.BaseMethod<IrSimpleFunctionSymbol>
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter { ): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
val irFunction = baseMethod.symbol.owner val irFunction = baseMethod.owner
require(irFunction.modality == Modality.FINAL) require(irFunction.modality == Modality.FINAL)
return createMethodAdapter(irFunction, baseMethod) return createMethodAdapter(irFunction, baseMethod)
} }
@@ -1551,21 +1567,21 @@ private fun ObjCExportCodeGenerator.createMethodAdapter(
val selectorName = request.base.selector val selectorName = request.base.selector
val methodBridge = request.base.bridge val methodBridge = request.base.bridge
val imp = generateObjCImp(request.implementation, request.base.symbol.owner, methodBridge) val imp = generateObjCImp(request.implementation, request.base.owner, methodBridge)
objCToKotlinMethodAdapter(selectorName, methodBridge, imp) objCToKotlinMethodAdapter(selectorName, methodBridge, imp)
} }
private fun ObjCExportCodeGenerator.createConstructorAdapter( private fun ObjCExportCodeGenerator.createConstructorAdapter(
baseMethod: ObjCMethodSpec.BaseMethod<IrConstructorSymbol> baseMethod: ObjCMethodSpec.BaseMethod<IrConstructorSymbol>
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter = createMethodAdapter(baseMethod.symbol.owner, baseMethod) ): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter = createMethodAdapter(baseMethod.owner, baseMethod)
private fun ObjCExportCodeGenerator.createArrayConstructorAdapter( private fun ObjCExportCodeGenerator.createArrayConstructorAdapter(
baseMethod: ObjCMethodSpec.BaseMethod<IrConstructorSymbol> baseMethod: ObjCMethodSpec.BaseMethod<IrConstructorSymbol>
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter { ): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
val selectorName = baseMethod.selector val selectorName = baseMethod.selector
val methodBridge = baseMethod.bridge val methodBridge = baseMethod.bridge
val irConstructor = baseMethod.symbol.owner val irConstructor = baseMethod.owner
val imp = generateObjCImpForArrayConstructor(irConstructor, methodBridge) val imp = generateObjCImpForArrayConstructor(irConstructor, methodBridge)
return objCToKotlinMethodAdapter(selectorName, methodBridge, imp) return objCToKotlinMethodAdapter(selectorName, methodBridge, imp)
@@ -1666,7 +1682,7 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
val virtualAdapters = type.kotlinMethods val virtualAdapters = type.kotlinMethods
.filter { .filter {
val irFunction = it.baseMethod.symbol.owner val irFunction = it.baseMethod.owner
irFunction.parentAsClass == irClass && irFunction.isOverridable irFunction.parentAsClass == irClass && irFunction.isOverridable
}.map { createMethodVirtualAdapter(it.baseMethod) } }.map { createMethodVirtualAdapter(it.baseMethod) }
@@ -1755,9 +1771,9 @@ private fun ObjCExportCodeGenerator.createReverseAdapters(
val methodsCoveredByInheritedAdapters = inheritedAdapters.flatMapTo(mutableSetOf()) { it.coveredMethods } val methodsCoveredByInheritedAdapters = inheritedAdapters.flatMapTo(mutableSetOf()) { it.coveredMethods }
val allBaseMethodsByIr = type.kotlinMethods.map { it.baseMethod }.associateBy { it.symbol.owner } val allBaseMethodsByIr = type.kotlinMethods.map { it.baseMethod }.associateBy { it.owner }
for (method in type.irClassSymbol.owner.simpleFunctions()) { for (method in type.irClassSymbol.owner.simpleFunctions().map { it.getLowered() }) {
val baseMethods = method.allOverriddenFunctions.mapNotNull { allBaseMethodsByIr[it] } val baseMethods = method.allOverriddenFunctions.mapNotNull { allBaseMethodsByIr[it] }
if (baseMethods.isEmpty()) continue if (baseMethods.isEmpty()) continue
@@ -1830,7 +1846,7 @@ private fun ObjCExportCodeGenerator.createDirectAdapters(
fun ObjCClassForKotlinClass.getAllRequiredDirectAdapters() = this.kotlinMethods.map { method -> fun ObjCClassForKotlinClass.getAllRequiredDirectAdapters() = this.kotlinMethods.map { method ->
DirectAdapterRequest( DirectAdapterRequest(
findImplementation(irClassSymbol.owner, method.baseMethod.symbol.owner, context), findImplementation(irClassSymbol.owner, method.baseMethod.owner, context),
method.baseMethod method.baseMethod
) )
} }
@@ -1841,9 +1857,9 @@ private fun ObjCExportCodeGenerator.createDirectAdapters(
return requiredAdapters.distinctBy { it.base.selector }.map { createMethodAdapter(it) } return requiredAdapters.distinctBy { it.base.selector }.map { createMethodAdapter(it) }
} }
private fun findImplementation(irClass: IrClass, method: IrSimpleFunction, context: Context): IrSimpleFunction? { private fun ObjCExportCodeGenerator.findImplementation(irClass: IrClass, method: IrSimpleFunction, context: Context): IrSimpleFunction? {
val override = irClass.simpleFunctions().singleOrNull { val override = irClass.simpleFunctions().singleOrNull {
method in it.allOverriddenFunctions method in it.getLowered().allOverriddenFunctions
} ?: error("no implementation for ${method.render()}\nin ${irClass.fqNameWhenAvailable}") } ?: error("no implementation for ${method.render()}\nin ${irClass.fqNameWhenAvailable}")
return OverriddenFunctionInfo(override, method).getImplementation(context) return OverriddenFunctionInfo(override, method).getImplementation(context)
} }
@@ -105,10 +105,11 @@ internal fun MethodBridge.parametersAssociated(
return this.paramBridges.map { return this.paramBridges.map {
when (it) { when (it) {
is MethodBridgeValueParameter.Mapped, MethodBridgeReceiver.Instance -> is MethodBridgeValueParameter.Mapped,
MethodBridgeReceiver.Instance,
is MethodBridgeValueParameter.SuspendCompletion ->
it to kotlinParameters.next() it to kotlinParameters.next()
is MethodBridgeValueParameter.SuspendCompletion,
MethodBridgeReceiver.Static, MethodBridgeSelector, MethodBridgeValueParameter.ErrorOutParameter -> MethodBridgeReceiver.Static, MethodBridgeSelector, MethodBridgeValueParameter.ErrorOutParameter ->
it to null it to null