[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
|
+result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrBuilderWithScope.getObjCClass(symbols: KonanSymbols, symbol: IrClassSymbol): IrExpression {
|
internal fun IrBuilderWithScope.getObjCClass(symbols: KonanSymbols, symbol: IrClassSymbol): IrExpression {
|
||||||
val classDescriptor = symbol.descriptor
|
val classDescriptor = symbol.descriptor
|
||||||
assert(!classDescriptor.isObjCMetaClass())
|
assert(!classDescriptor.isObjCMetaClass())
|
||||||
return irCall(symbols.interopGetObjCClass, symbols.nativePtrType, listOf(symbol.typeWithStarProjections))
|
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) {
|
if (!function.isTypedIntrinsic) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val intrinsicType = getIntrinsicType(callSite)
|
return when (getIntrinsicType(callSite)) {
|
||||||
return when (intrinsicType) {
|
|
||||||
IntrinsicType.IMMUTABLE_BLOB -> {
|
IntrinsicType.IMMUTABLE_BLOB -> {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val arg = callSite.getValueArgument(0) as IrConst<String>
|
val arg = callSite.getValueArgument(0) as IrConst<String>
|
||||||
context.llvm.staticData.createImmutableBlob(arg)
|
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 -> {
|
IntrinsicType.OBJC_GET_SELECTOR -> {
|
||||||
val selector = (callSite.getValueArgument(0) as IrConst<*>).value as String
|
val selector = (callSite.getValueArgument(0) as IrConst<*>).value as String
|
||||||
environment.functionGenerationContext.genObjCSelector(selector)
|
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)
|
lifetime = resultLifetime(callee), exceptionHandler = currentCodeContext.exceptionHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: OBJC-CONSTRUCTOR-CALL. Move to InteropLowering.
|
constructedClass.isObjCClass() -> error("Call should've been lowered: ${callee.dump()}")
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee))
|
else -> functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee))
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-35
@@ -672,18 +672,21 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
|
|||||||
expression.transformChildrenVoid()
|
expression.transformChildrenVoid()
|
||||||
|
|
||||||
val callee = expression.symbol.owner
|
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) }
|
val constructedClass = callee.constructedClass
|
||||||
assert(expression.extensionReceiver == null)
|
val initMethodInfo = initMethod.getExternalObjCMethodInfo()!!
|
||||||
assert(expression.dispatchReceiver == null)
|
return builder.at(expression).run {
|
||||||
|
val classPtr = getObjCClass(constructedClass.symbol)
|
||||||
val constructedClass = callee.constructedClass
|
ensureObjCReferenceNotNull(callAllocAndInit(classPtr, initMethodInfo, arguments, expression, initMethod))
|
||||||
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 =
|
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 {
|
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
val function = expression.symbol.owner
|
val callee = expression.symbol.owner
|
||||||
val inlinedClass = function.returnType.getInlinedClassNative()
|
val inlinedClass = callee.returnType.getInlinedClassNative()
|
||||||
if (inlinedClass?.descriptor == interop.cPointer || inlinedClass?.descriptor == interop.nativePointed) {
|
if (inlinedClass?.descriptor == interop.cPointer || inlinedClass?.descriptor == interop.nativePointed) {
|
||||||
context.reportCompilationError("Native interop types constructors must not be called directly",
|
context.reportCompilationError("Native interop types constructors must not be called directly",
|
||||||
irFile, expression)
|
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 {
|
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)
|
expression.transformChildrenVoid(this)
|
||||||
builder.at(expression)
|
builder.at(expression)
|
||||||
@@ -957,8 +1014,6 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi
|
|||||||
|
|
||||||
tryGenerateInteropConstantRead(expression)?.let { return it }
|
tryGenerateInteropConstantRead(expression)?.let { return it }
|
||||||
|
|
||||||
val intrinsicType = tryGetIntrinsicType(expression)
|
|
||||||
|
|
||||||
if (intrinsicType != null) {
|
if (intrinsicType != null) {
|
||||||
return when (intrinsicType) {
|
return when (intrinsicType) {
|
||||||
IntrinsicType.INTEROP_BITS_TO_FLOAT -> {
|
IntrinsicType.INTEROP_BITS_TO_FLOAT -> {
|
||||||
@@ -1097,26 +1152,6 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi
|
|||||||
IntrinsicType.INTEROP_MEMORY_COPY -> {
|
IntrinsicType.INTEROP_MEMORY_COPY -> {
|
||||||
TODO("So far unsupported")
|
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 -> {
|
IntrinsicType.WORKER_EXECUTE -> {
|
||||||
val irCallableReference = unwrapStaticFunctionArgument(expression.getValueArgument(2)!!)
|
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.DirectedGraph
|
||||||
import org.jetbrains.kotlin.backend.konan.DirectedGraphNode
|
import org.jetbrains.kotlin.backend.konan.DirectedGraphNode
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
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)
|
internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.FunctionSymbol)
|
||||||
: DirectedGraphNode<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) =
|
private inline fun DataFlowIR.FunctionBody.forEachCallSite(block: (DataFlowIR.Node.Call) -> Unit) =
|
||||||
nodes.forEach { node ->
|
nodes.forEach { node ->
|
||||||
when (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.Call -> block(node)
|
||||||
|
|
||||||
is DataFlowIR.Node.Singleton ->
|
is DataFlowIR.Node.Singleton ->
|
||||||
|
|||||||
Reference in New Issue
Block a user