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 blockLiteralType = codegen.runtime.getStructType("Block_literal_1")
val invokePtr = structGep(bitcast(pointerType(blockLiteralType), blockPtr), 3) 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( private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
@@ -123,7 +123,15 @@ private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
resultLifetime 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( get() = functionType(
if (returnsVoid) voidType else int8TypePtr, if (returnsVoid) voidType else int8TypePtr,
false, false,
@@ -133,7 +141,7 @@ private val BlockPointerBridge.blockInvokeLlvmType: LLVMTypeRef
private val BlockPointerBridge.nameSuffix: String private val BlockPointerBridge.nameSuffix: String
get() = numberOfParameters.toString() + if (returnsVoid) "V" else "" 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 kRefSharedHolderType = LLVMGetTypeByName(codegen.runtime.llvmModule, "class.KRefSharedHolder")!!
private val blockLiteralType = structType( 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) = fun org.jetbrains.kotlin.backend.konan.Context.LongInt(value: Long) =
if (is64BitLong()) Int64(value) else Int32(value.toInt()) if (is64BitLong()) Int64(value) else Int32(value.toInt())
private fun generateDescriptorForBlockAdapterToFunction(bridge: BlockPointerBridge): ConstValue { private fun generateDescriptorForBlock(blockType: BlockType): ConstValue {
val numberOfParameters = bridge.numberOfParameters val numberOfParameters = blockType.numberOfParameters
val signature = buildString { val signature = buildString {
append(if (bridge.returnsVoid) 'v' else '@') append(if (blockType.returnsVoid) 'v' else '@')
val pointerSize = codegen.runtime.pointerSize val pointerSize = codegen.runtime.pointerSize
append(pointerSize * (numberOfParameters + 1)) append(pointerSize * (numberOfParameters + 1))
@@ -217,35 +225,23 @@ internal class BlockAdapterToFunctionGenerator(private val codegen: CodeGenerato
} }
private fun ObjCExportCodeGeneratorBase.generateInvoke(
private fun ObjCExportCodeGeneratorBase.generateInvoke(bridge: BlockPointerBridge): ConstPointer { blockType: BlockType,
val numberOfParameters = bridge.numberOfParameters invokeName: String,
genBody: FunctionGenerationContext.(LLVMValueRef, List<LLVMValueRef>) -> Unit
val result = generateFunction(codegen, bridge.blockInvokeLlvmType, "invokeBlock${bridge.nameSuffix}") { ): ConstPointer {
val result = generateFunction(codegen, blockType.blockInvokeLlvmType, invokeName) {
val blockPtr = bitcast(pointerType(blockLiteralType), param(0)) val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
val kotlinFunction = call( val kotlinObject = call(
context.llvm.kRefSharedHolderRef, context.llvm.kRefSharedHolderRef,
listOf(structGep(blockPtr, 1)), listOf(structGep(blockPtr, 1)),
exceptionHandler = ExceptionHandler.Caller, exceptionHandler = ExceptionHandler.Caller,
verbatim = true verbatim = true
) )
val args = (1 .. numberOfParameters).map { index -> val arguments = (1 .. blockType.numberOfParameters).map { index -> param(index) }
objCReferenceToKotlin(param(index), Lifetime.ARGUMENT)
}
val invokeMethod = context.ir.symbols.functionN(numberOfParameters).owner.simpleFunctions() genBody(kotlinObject, arguments)
.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))
}
}.also { }.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage) LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
} }
@@ -253,16 +249,48 @@ internal class BlockAdapterToFunctionGenerator(private val codegen: CodeGenerato
return constPointer(result) 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( val blockDescriptor = codegen.staticData.placeGlobal(
"", "",
generateDescriptorForBlockAdapterToFunction(bridge) generateDescriptorForBlock(blockType)
) )
return generateFunction( return generateFunction(
codegen, codegen,
functionType(int8TypePtr, false, codegen.kObjHeaderPtr), functionType(int8TypePtr, false, codegen.kObjHeaderPtr),
"convertFunction${bridge.nameSuffix}" convertName
) { ) {
val kotlinRef = param(0) val kotlinRef = param(0)
ifThen(icmpEq(kotlinRef, kNullObjHeaderPtr)) { ifThen(icmpEq(kotlinRef, kNullObjHeaderPtr)) {
@@ -279,7 +307,7 @@ internal class BlockAdapterToFunctionGenerator(private val codegen: CodeGenerato
val reserved = Int32(0).llvm val reserved = Int32(0).llvm
val invokeType = pointerType(functionType(voidType, true, int8TypePtr)) 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 descriptor = blockDescriptor.llvmGlobal
val blockOnStack = alloca(blockLiteralType) val blockOnStack = alloca(blockLiteralType)
@@ -86,12 +86,12 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
generateBlockToKotlinFunctionConverter(bridge) generateBlockToKotlinFunctionConverter(bridge)
} }
private val blockAdapterToFunctionGenerator = BlockAdapterToFunctionGenerator(this.codegen) private val blockGenerator = BlockGenerator(this.codegen)
private val functionToBlockConverterCache = mutableMapOf<BlockPointerBridge, LLVMValueRef>() private val functionToBlockConverterCache = mutableMapOf<BlockPointerBridge, LLVMValueRef>()
internal fun kotlinFunctionToBlockConverter(bridge: BlockPointerBridge): LLVMValueRef = internal fun kotlinFunctionToBlockConverter(bridge: BlockPointerBridge): LLVMValueRef =
functionToBlockConverterCache.getOrPut(bridge) { functionToBlockConverterCache.getOrPut(bridge) {
blockAdapterToFunctionGenerator.run { blockGenerator.run {
generateConvertFunctionToBlock(bridge) generateConvertFunctionToBlock(bridge)
} }
} }