Refactor block generator in ObjCExport
This commit is contained in:
committed by
SvyatoslavScherbina
parent
6d65722b67
commit
4e048b5e25
+59
-31
@@ -110,7 +110,7 @@ private fun FunctionGenerationContext.loadBlockInvoke(
|
||||
val blockLiteralType = codegen.runtime.getStructType("Block_literal_1")
|
||||
val invokePtr = structGep(bitcast(pointerType(blockLiteralType), blockPtr), 3)
|
||||
|
||||
return bitcast(pointerType(bridge.blockInvokeLlvmType), load(invokePtr))
|
||||
return bitcast(pointerType(bridge.blockType.blockInvokeLlvmType), load(invokePtr))
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
|
||||
@@ -123,7 +123,15 @@ private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
|
||||
resultLifetime
|
||||
)
|
||||
|
||||
private val BlockPointerBridge.blockInvokeLlvmType: LLVMTypeRef
|
||||
private val BlockPointerBridge.blockType: BlockType
|
||||
get() = BlockType(numberOfParameters = this.numberOfParameters, returnsVoid = this.returnsVoid)
|
||||
|
||||
/**
|
||||
* Type of block having [numberOfParameters] reference-typed parameters and reference- or void-typed return value.
|
||||
*/
|
||||
internal data class BlockType(val numberOfParameters: Int, val returnsVoid: Boolean)
|
||||
|
||||
private val BlockType.blockInvokeLlvmType: LLVMTypeRef
|
||||
get() = functionType(
|
||||
if (returnsVoid) voidType else int8TypePtr,
|
||||
false,
|
||||
@@ -133,7 +141,7 @@ private val BlockPointerBridge.blockInvokeLlvmType: LLVMTypeRef
|
||||
private val BlockPointerBridge.nameSuffix: String
|
||||
get() = numberOfParameters.toString() + if (returnsVoid) "V" else ""
|
||||
|
||||
internal class BlockAdapterToFunctionGenerator(private val codegen: CodeGenerator) {
|
||||
internal class BlockGenerator(private val codegen: CodeGenerator) {
|
||||
private val kRefSharedHolderType = LLVMGetTypeByName(codegen.runtime.llvmModule, "class.KRefSharedHolder")!!
|
||||
|
||||
private val blockLiteralType = structType(
|
||||
@@ -188,11 +196,11 @@ internal class BlockAdapterToFunctionGenerator(private val codegen: CodeGenerato
|
||||
fun org.jetbrains.kotlin.backend.konan.Context.LongInt(value: Long) =
|
||||
if (is64BitLong()) Int64(value) else Int32(value.toInt())
|
||||
|
||||
private fun generateDescriptorForBlockAdapterToFunction(bridge: BlockPointerBridge): ConstValue {
|
||||
val numberOfParameters = bridge.numberOfParameters
|
||||
private fun generateDescriptorForBlock(blockType: BlockType): ConstValue {
|
||||
val numberOfParameters = blockType.numberOfParameters
|
||||
|
||||
val signature = buildString {
|
||||
append(if (bridge.returnsVoid) 'v' else '@')
|
||||
append(if (blockType.returnsVoid) 'v' else '@')
|
||||
val pointerSize = codegen.runtime.pointerSize
|
||||
append(pointerSize * (numberOfParameters + 1))
|
||||
|
||||
@@ -217,35 +225,23 @@ internal class BlockAdapterToFunctionGenerator(private val codegen: CodeGenerato
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun ObjCExportCodeGeneratorBase.generateInvoke(bridge: BlockPointerBridge): ConstPointer {
|
||||
val numberOfParameters = bridge.numberOfParameters
|
||||
|
||||
val result = generateFunction(codegen, bridge.blockInvokeLlvmType, "invokeBlock${bridge.nameSuffix}") {
|
||||
private fun ObjCExportCodeGeneratorBase.generateInvoke(
|
||||
blockType: BlockType,
|
||||
invokeName: String,
|
||||
genBody: FunctionGenerationContext.(LLVMValueRef, List<LLVMValueRef>) -> Unit
|
||||
): ConstPointer {
|
||||
val result = generateFunction(codegen, blockType.blockInvokeLlvmType, invokeName) {
|
||||
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
|
||||
val kotlinFunction = call(
|
||||
val kotlinObject = call(
|
||||
context.llvm.kRefSharedHolderRef,
|
||||
listOf(structGep(blockPtr, 1)),
|
||||
exceptionHandler = ExceptionHandler.Caller,
|
||||
verbatim = true
|
||||
)
|
||||
|
||||
val args = (1 .. numberOfParameters).map { index ->
|
||||
objCReferenceToKotlin(param(index), Lifetime.ARGUMENT)
|
||||
}
|
||||
val arguments = (1 .. blockType.numberOfParameters).map { index -> param(index) }
|
||||
|
||||
val invokeMethod = context.ir.symbols.functionN(numberOfParameters).owner.simpleFunctions()
|
||||
.single { it.name == OperatorNameConventions.INVOKE }
|
||||
|
||||
val callee = lookupVirtualImpl(kotlinFunction, invokeMethod)
|
||||
|
||||
val result = callFromBridge(callee, listOf(kotlinFunction) + args, Lifetime.ARGUMENT)
|
||||
|
||||
if (bridge.returnsVoid) {
|
||||
ret(null)
|
||||
} else {
|
||||
ret(kotlinReferenceToObjC(result))
|
||||
}
|
||||
genBody(kotlinObject, arguments)
|
||||
}.also {
|
||||
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
|
||||
}
|
||||
@@ -253,16 +249,48 @@ internal class BlockAdapterToFunctionGenerator(private val codegen: CodeGenerato
|
||||
return constPointer(result)
|
||||
}
|
||||
|
||||
fun ObjCExportCodeGeneratorBase.generateConvertFunctionToBlock(bridge: BlockPointerBridge): LLVMValueRef {
|
||||
fun ObjCExportCodeGeneratorBase.generateConvertFunctionToBlock(
|
||||
bridge: BlockPointerBridge
|
||||
): LLVMValueRef {
|
||||
return generateWrapKotlinObjectToBlock(
|
||||
bridge.blockType,
|
||||
convertName = "convertFunction${bridge.nameSuffix}",
|
||||
invokeName = "invokeBlock${bridge.nameSuffix}"
|
||||
) { kotlinFunction, arguments ->
|
||||
val numberOfParameters = bridge.numberOfParameters
|
||||
|
||||
val kotlinArguments = arguments.map { objCReferenceToKotlin(it, Lifetime.ARGUMENT) }
|
||||
|
||||
val invokeMethod = context.ir.symbols.functionN(numberOfParameters).owner.simpleFunctions()
|
||||
.single { it.name == OperatorNameConventions.INVOKE }
|
||||
|
||||
val callee = lookupVirtualImpl(kotlinFunction, invokeMethod)
|
||||
|
||||
val result = callFromBridge(callee, listOf(kotlinFunction) + kotlinArguments, Lifetime.ARGUMENT)
|
||||
|
||||
if (bridge.returnsVoid) {
|
||||
ret(null)
|
||||
} else {
|
||||
ret(kotlinReferenceToObjC(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ObjCExportCodeGeneratorBase.generateWrapKotlinObjectToBlock(
|
||||
blockType: BlockType,
|
||||
convertName: String,
|
||||
invokeName: String,
|
||||
genBlockBody: FunctionGenerationContext.(LLVMValueRef, List<LLVMValueRef>) -> Unit
|
||||
): LLVMValueRef {
|
||||
val blockDescriptor = codegen.staticData.placeGlobal(
|
||||
"",
|
||||
generateDescriptorForBlockAdapterToFunction(bridge)
|
||||
generateDescriptorForBlock(blockType)
|
||||
)
|
||||
|
||||
return generateFunction(
|
||||
codegen,
|
||||
functionType(int8TypePtr, false, codegen.kObjHeaderPtr),
|
||||
"convertFunction${bridge.nameSuffix}"
|
||||
convertName
|
||||
) {
|
||||
val kotlinRef = param(0)
|
||||
ifThen(icmpEq(kotlinRef, kNullObjHeaderPtr)) {
|
||||
@@ -279,7 +307,7 @@ internal class BlockAdapterToFunctionGenerator(private val codegen: CodeGenerato
|
||||
val reserved = Int32(0).llvm
|
||||
|
||||
val invokeType = pointerType(functionType(voidType, true, int8TypePtr))
|
||||
val invoke = generateInvoke(bridge).bitcast(invokeType).llvm
|
||||
val invoke = generateInvoke(blockType, invokeName, genBlockBody).bitcast(invokeType).llvm
|
||||
val descriptor = blockDescriptor.llvmGlobal
|
||||
|
||||
val blockOnStack = alloca(blockLiteralType)
|
||||
|
||||
+2
-2
@@ -86,12 +86,12 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
|
||||
generateBlockToKotlinFunctionConverter(bridge)
|
||||
}
|
||||
|
||||
private val blockAdapterToFunctionGenerator = BlockAdapterToFunctionGenerator(this.codegen)
|
||||
private val blockGenerator = BlockGenerator(this.codegen)
|
||||
private val functionToBlockConverterCache = mutableMapOf<BlockPointerBridge, LLVMValueRef>()
|
||||
|
||||
internal fun kotlinFunctionToBlockConverter(bridge: BlockPointerBridge): LLVMValueRef =
|
||||
functionToBlockConverterCache.getOrPut(bridge) {
|
||||
blockAdapterToFunctionGenerator.run {
|
||||
blockGenerator.run {
|
||||
generateConvertFunctionToBlock(bridge)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user