Refactor block generator in ObjCExport

This commit is contained in:
Svyatoslav Scherbina
2020-02-18 10:55:40 +03:00
committed by SvyatoslavScherbina
parent 6d65722b67
commit 4e048b5e25
2 changed files with 61 additions and 33 deletions
@@ -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)
@@ -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)
}
}