From 97d3d39187c48c2eeb46f4d289c5e2243fa258ac Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Tue, 2 Jun 2020 20:32:07 +0500 Subject: [PATCH] [IR][codegen] Moved objc allocs from codegen to InteropLowering --- .../kotlin/backend/konan/cgen/CBridgeGen.kt | 2 +- .../backend/konan/llvm/IntrinsicGenerator.kt | 12 +- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 16 +-- .../backend/konan/lower/InteropLowering.kt | 105 ++++++++++++------ .../konan/optimizations/CallGraphBuilder.kt | 27 ----- 5 files changed, 73 insertions(+), 89 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/cgen/CBridgeGen.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/cgen/CBridgeGen.kt index f6891989ac2..8f46c4bad8b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/cgen/CBridgeGen.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/cgen/CBridgeGen.kt @@ -386,7 +386,7 @@ internal fun KotlinStubs.generateObjCCall( +result } -private fun IrBuilderWithScope.getObjCClass(symbols: KonanSymbols, symbol: IrClassSymbol): IrExpression { +internal fun IrBuilderWithScope.getObjCClass(symbols: KonanSymbols, symbol: IrClassSymbol): IrExpression { val classDescriptor = symbol.descriptor assert(!classDescriptor.isObjCMetaClass()) return irCall(symbols.interopGetObjCClass, symbols.nativePtrType, listOf(symbol.typeWithStarProjections)) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt index 81ad60bccae..af3b3237e39 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt @@ -144,22 +144,12 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv if (!function.isTypedIntrinsic) { return null } - val intrinsicType = getIntrinsicType(callSite) - return when (intrinsicType) { + return when (getIntrinsicType(callSite)) { IntrinsicType.IMMUTABLE_BLOB -> { @Suppress("UNCHECKED_CAST") val arg = callSite.getValueArgument(0) as IrConst context.llvm.staticData.createImmutableBlob(arg) } - IntrinsicType.OBJC_INIT_BY -> { - val receiver = environment.evaluateExpression(callSite.extensionReceiver!!) - val irConstructorCall = callSite.getValueArgument(0) as IrConstructorCall - val constructorDescriptor = irConstructorCall.symbol.owner - val constructorArgs = environment.evaluateExplicitArgs(irConstructorCall) - val args = listOf(receiver) + constructorArgs - environment.evaluateCall(constructorDescriptor, args, Lifetime.IRRELEVANT) - receiver - } IntrinsicType.OBJC_GET_SELECTOR -> { val selector = (callSite.getValueArgument(0) as IrConst<*>).value as String environment.functionGenerationContext.genObjCSelector(selector) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index b6782b4d60a..e8bbd22832e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -2142,21 +2142,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map { - assert(constructedClass.isKotlinObjCClass()) // Calls to other ObjC class constructors must be lowered. - val symbols = context.ir.symbols - val rawPtr = callDirect( - symbols.interopAllocObjCObject.owner, - listOf(genGetObjCClass(constructedClass)), - Lifetime.IRRELEVANT - ) - - callDirect(symbols.interopInterpretObjCPointer.owner, listOf(rawPtr), resultLifetime(callee)).also { - // Balance pointer retained by alloc: - callDirect(symbols.interopObjCRelease.owner, listOf(rawPtr), Lifetime.IRRELEVANT) - } - } + constructedClass.isObjCClass() -> error("Call should've been lowered: ${callee.dump()}") else -> functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee)) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt index b4821f632d7..fc1c6f13f8d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt @@ -672,18 +672,21 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor expression.transformChildrenVoid() val callee = expression.symbol.owner - val initMethod = callee.getObjCInitMethod() ?: return expression + val initMethod = callee.getObjCInitMethod() + if (initMethod != null) { + val arguments = callee.valueParameters.map { expression.getValueArgument(it.index) } + assert(expression.extensionReceiver == null) + assert(expression.dispatchReceiver == null) - val arguments = callee.valueParameters.map { expression.getValueArgument(it.index) } - assert(expression.extensionReceiver == null) - assert(expression.dispatchReceiver == null) - - val constructedClass = callee.constructedClass - val initMethodInfo = initMethod.getExternalObjCMethodInfo()!! - return builder.at(expression).run { - val classPtr = getObjCClass(constructedClass.symbol) - ensureObjCReferenceNotNull(callAllocAndInit(classPtr, initMethodInfo, arguments, expression, initMethod)) + val constructedClass = callee.constructedClass + val initMethodInfo = initMethod.getExternalObjCMethodInfo()!! + return builder.at(expression).run { + val classPtr = getObjCClass(constructedClass.symbol) + ensureObjCReferenceNotNull(callAllocAndInit(classPtr, initMethodInfo, arguments, expression, initMethod)) + } } + + return expression } private fun IrBuilderWithScope.ensureObjCReferenceNotNull(expression: IrExpression): IrExpression = @@ -896,13 +899,35 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi override fun visitConstructorCall(expression: IrConstructorCall): IrExpression { expression.transformChildrenVoid(this) - val function = expression.symbol.owner - val inlinedClass = function.returnType.getInlinedClassNative() + val callee = expression.symbol.owner + val inlinedClass = callee.returnType.getInlinedClassNative() if (inlinedClass?.descriptor == interop.cPointer || inlinedClass?.descriptor == interop.nativePointed) { context.reportCompilationError("Native interop types constructors must not be called directly", irFile, expression) } - return expression + + val constructedClass = callee.constructedClass + if (!constructedClass.isObjCClass()) + return expression + + assert(constructedClass.isKotlinObjCClass()) // Calls to other ObjC class constructors must be lowered. + return builder.at(expression).irBlock { + val rawPtr = irTemporary(irCall(symbols.interopAllocObjCObject.owner).apply { + putValueArgument(0, getObjCClass(symbols, constructedClass.symbol)) + }) + val instance = irTemporary(irCall(symbols.interopInterpretObjCPointer.owner).apply { + putValueArgument(0, irGet(rawPtr)) + }) + // Balance pointer retained by alloc: + +irCall(symbols.interopObjCRelease.owner).apply { + putValueArgument(0, irGet(rawPtr)) + } + +irCall(symbols.initInstance).apply { + putValueArgument(0, irGet(instance)) + putValueArgument(1, expression) + } + +irGet(instance) + } } /** @@ -933,6 +958,38 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi } override fun visitCall(expression: IrCall): IrExpression { + val intrinsicType = tryGetIntrinsicType(expression) + if (intrinsicType == IntrinsicType.OBJC_INIT_BY) { + // Need to do this separately as otherwise [expression.transformChildrenVoid(this)] would be called + // and the [IrConstructorCall] would be transformed which is not what we want. + val intrinsic = interop.objCObjectInitBy.name + + val argument = expression.getValueArgument(0)!! + val constructorCall = argument as? IrConstructorCall + ?: context.reportCompilationError("Argument of '$intrinsic' must be a constructor call", + irFile, argument) + + val constructedClass = constructorCall.symbol.owner.constructedClass + + val extensionReceiver = expression.extensionReceiver!! + if (extensionReceiver !is IrGetValue || + !extensionReceiver.symbol.owner.isDispatchReceiverFor(constructedClass)) { + + context.reportCompilationError("Receiver of '$intrinsic' must be a 'this' of the constructed class", + irFile, extensionReceiver) + } + + constructorCall.transformChildrenVoid(this) + + return builder.at(expression).irBlock { + val instance = extensionReceiver.symbol.owner + +irCall(symbols.initInstance).apply { + putValueArgument(0, irGet(instance)) + putValueArgument(1, constructorCall) + } + +irGet(instance) + } + } expression.transformChildrenVoid(this) builder.at(expression) @@ -957,8 +1014,6 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi tryGenerateInteropConstantRead(expression)?.let { return it } - val intrinsicType = tryGetIntrinsicType(expression) - if (intrinsicType != null) { return when (intrinsicType) { IntrinsicType.INTEROP_BITS_TO_FLOAT -> { @@ -1097,26 +1152,6 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi IntrinsicType.INTEROP_MEMORY_COPY -> { TODO("So far unsupported") } - IntrinsicType.OBJC_INIT_BY -> { - val intrinsic = interop.objCObjectInitBy.name - - val argument = expression.getValueArgument(0)!! - val constructedClass = (argument as? IrConstructorCall)?.symbol?.owner?.constructedClass - - if (constructedClass == null) { - context.reportCompilationError("Argument of '$intrinsic' must be a constructor call", - irFile, argument) - } - - val extensionReceiver = expression.extensionReceiver!! - if (extensionReceiver !is IrGetValue || - !extensionReceiver.symbol.owner.isDispatchReceiverFor(constructedClass)) { - - context.reportCompilationError("Receiver of '$intrinsic' must be a 'this' of the constructed class", - irFile, extensionReceiver) - } - expression - } IntrinsicType.WORKER_EXECUTE -> { val irCallableReference = unwrapStaticFunctionArgument(expression.getValueArgument(2)!!) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt index 21b524645bb..aef5297cc6d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt @@ -10,8 +10,6 @@ import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.konan.DirectedGraph import org.jetbrains.kotlin.backend.konan.DirectedGraphNode import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.isObjCClass -import org.jetbrains.kotlin.ir.util.parentAsClass internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.FunctionSymbol) : DirectedGraphNode { @@ -111,31 +109,6 @@ internal class CallGraphBuilder(val context: Context, private inline fun DataFlowIR.FunctionBody.forEachCallSite(block: (DataFlowIR.Node.Call) -> Unit) = nodes.forEach { node -> when (node) { - // TODO: OBJC-CONSTRUCTOR-CALL - is DataFlowIR.Node.NewObject -> { - block(node) - if (node.irCallSite?.symbol?.owner?.parentAsClass?.isObjCClass() == true) { - block(DataFlowIR.Node.Call( - callee = moduleDFG.symbolTable.mapFunction(symbols.interopAllocObjCObject.owner), - arguments = listOf(DataFlowIR.Edge(DataFlowIR.Node.Null, null)), - returnType = moduleDFG.symbolTable.mapType(symbols.interopAllocObjCObject.owner.returnType), - irCallSite = null) - ) - block(DataFlowIR.Node.Call( - callee = moduleDFG.symbolTable.mapFunction(symbols.interopInterpretObjCPointer.owner), - arguments = listOf(DataFlowIR.Edge(DataFlowIR.Node.Null, null)), - returnType = moduleDFG.symbolTable.mapType(symbols.interopInterpretObjCPointer.owner.returnType), - irCallSite = null) - ) - block(DataFlowIR.Node.Call( - callee = moduleDFG.symbolTable.mapFunction(symbols.interopObjCRelease.owner), - arguments = listOf(DataFlowIR.Edge(DataFlowIR.Node.Null, null)), - returnType = moduleDFG.symbolTable.mapType(symbols.interopObjCRelease.owner.returnType), - irCallSite = null) - ) - } - } - is DataFlowIR.Node.Call -> block(node) is DataFlowIR.Node.Singleton ->