[IR][codegen] Moved objc allocs from codegen to InteropLowering
This commit is contained in:
+1
-1
@@ -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))
|
||||
|
||||
+1
-11
@@ -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<String>
|
||||
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)
|
||||
|
||||
+1
-15
@@ -2142,21 +2142,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
lifetime = resultLifetime(callee), exceptionHandler = currentCodeContext.exceptionHandler)
|
||||
}
|
||||
|
||||
// TODO: OBJC-CONSTRUCTOR-CALL. Move to InteropLowering.
|
||||
constructedClass.isObjCClass() -> {
|
||||
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))
|
||||
}
|
||||
|
||||
+70
-35
@@ -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)!!)
|
||||
|
||||
|
||||
-27
@@ -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<DataFlowIR.FunctionSymbol> {
|
||||
@@ -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 ->
|
||||
|
||||
Reference in New Issue
Block a user