diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index b4c2b6c95b3..3d676c8679f 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -121,11 +121,13 @@ val LLVMValueRef.isConst:Boolean get() = (LLVMIsConstant(this) == 1) -internal inline fun generateFunction(codegen: CodeGenerator, - function: IrFunction, - startLocation: LocationInfo?, - endLocation: LocationInfo?, - code: FunctionGenerationContext.(FunctionGenerationContext) -> R) { +internal inline fun generateFunction( + codegen: CodeGenerator, + function: IrFunction, + startLocation: LocationInfo?, + endLocation: LocationInfo?, + code: FunctionGenerationContext.() -> Unit +) { val llvmFunction = codegen.llvmFunction(function) val isCToKotlinBridge = function.origin == CBridgeOrigin.C_TO_KOTLIN_BRIDGE @@ -155,11 +157,24 @@ internal inline fun generateFunction(codegen: CodeGenerator, LLVMVerifyFunction(llvmFunction, LLVMVerifierFailureAction.LLVMAbortProcessAction) } +internal inline fun FunctionGenerationContextBuilder.generate(code: T.() -> Unit): LLVMValueRef { + val functionGenerationContext = this.build() + return try { + generateFunctionBody(functionGenerationContext, code) + functionGenerationContext.function + } finally { + functionGenerationContext.dispose() + } +} -internal inline fun generateFunction(codegen: CodeGenerator, function: LLVMValueRef, - startLocation: LocationInfo? = null, endLocation: LocationInfo? = null, - switchToRunnable: Boolean = false, - code:FunctionGenerationContext.(FunctionGenerationContext) -> R) { +internal inline fun generateFunction( + codegen: CodeGenerator, + function: LLVMValueRef, + startLocation: LocationInfo? = null, + endLocation: LocationInfo? = null, + switchToRunnable: Boolean = false, + code: FunctionGenerationContext.() -> Unit +) { val functionGenerationContext = FunctionGenerationContext( function, codegen, @@ -179,7 +194,7 @@ internal inline fun generateFunction( functionType: LLVMTypeRef, name: String, switchToRunnable: Boolean = false, - block: FunctionGenerationContext.(FunctionGenerationContext) -> Unit + block: FunctionGenerationContext.() -> Unit ): LLVMValueRef { val function = addLlvmFunctionWithDefaultAttributes( codegen.context, @@ -192,10 +207,10 @@ internal inline fun generateFunction( } // TODO: Consider using different abstraction than `FunctionGenerationContext` for `generateFunctionNoRuntime`. -internal inline fun generateFunctionNoRuntime( +internal inline fun generateFunctionNoRuntime( codegen: CodeGenerator, function: LLVMValueRef, - code: FunctionGenerationContext.(FunctionGenerationContext) -> R, + code: FunctionGenerationContext.() -> Unit, ) { val functionGenerationContext = FunctionGenerationContext(function, codegen, null, null, switchToRunnable = false) try { @@ -214,7 +229,7 @@ internal inline fun generateFunctionNoRuntime( codegen: CodeGenerator, functionType: LLVMTypeRef, name: String, - code: FunctionGenerationContext.(FunctionGenerationContext) -> Unit, + code: FunctionGenerationContext.() -> Unit, ): LLVMValueRef { val function = addLlvmFunctionWithDefaultAttributes( codegen.context, @@ -226,11 +241,11 @@ internal inline fun generateFunctionNoRuntime( return function } -private inline fun generateFunctionBody( - functionGenerationContext: FunctionGenerationContext, - code: FunctionGenerationContext.(FunctionGenerationContext) -> R) { +private inline fun generateFunctionBody( + functionGenerationContext: T, + code: T.() -> Unit) { functionGenerationContext.prologue() - functionGenerationContext.code(functionGenerationContext) + functionGenerationContext.code() if (!functionGenerationContext.isAfterTerminator()) functionGenerationContext.unreachable() functionGenerationContext.epilogue() @@ -387,12 +402,46 @@ internal class StackLocalsManagerImpl( } } -internal class FunctionGenerationContext(val function: LLVMValueRef, - val codegen: CodeGenerator, - private val startLocation: LocationInfo?, - private val endLocation: LocationInfo?, - private val switchToRunnable: Boolean, - internal val irFunction: IrFunction? = null): ContextUtils { +internal abstract class FunctionGenerationContextBuilder( + val function: LLVMValueRef, + val codegen: CodeGenerator +) { + constructor(functionType: LLVMTypeRef, functionName: String, codegen: CodeGenerator) : + this( + addLlvmFunctionWithDefaultAttributes( + codegen.context, + codegen.context.llvmModule!!, + functionName, + functionType + ), + codegen + ) + + var startLocation: LocationInfo? = null + var endLocation: LocationInfo? = null + var switchToRunnable = false + var irFunction: IrFunction? = null + + abstract fun build(): T +} + +internal open class FunctionGenerationContext( + val function: LLVMValueRef, + val codegen: CodeGenerator, + private val startLocation: LocationInfo?, + private val endLocation: LocationInfo?, + private val switchToRunnable: Boolean, + internal val irFunction: IrFunction? = null +) : ContextUtils { + + constructor(builder: FunctionGenerationContextBuilder<*>) : this( + function = builder.function, + codegen = builder.codegen, + startLocation = builder.startLocation, + endLocation = builder.endLocation, + switchToRunnable = builder.switchToRunnable, + irFunction = builder.irFunction + ) override val context = codegen.context val vars = VariableManager(this) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 29c9af9ab4a..d9608ed70d4 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -371,7 +371,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) { - using(FunctionScope(fileInitFunction, it)) { + using(FunctionScope(fileInitFunction, this)) { val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext) using(parameterScope) usingParameterScope@{ using(VariableScope()) usingVariableScope@{ @@ -388,7 +388,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) { - using(FunctionScope(fileInitFunction, it)) { + using(FunctionScope(fileInitFunction, this)) { val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext) using(parameterScope) usingParameterScope@{ using(VariableScope()) usingVariableScope@{ @@ -474,7 +474,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map kotlinReferenceToObjC(param(index + 1)) } @@ -71,11 +70,10 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter( immutable = true ) - return generateFunction( - codegen, + return functionGenerator( functionType(codegen.kObjHeaderPtr, false, int8TypePtr, codegen.kObjHeaderPtrPtr), "convertBlock${bridge.nameSuffix}" - ) { + ).generate { val blockPtr = param(0) ifThen(icmpEq(blockPtr, kNullInt8Ptr)) { ret(kNullObjHeaderPtr) @@ -235,7 +233,9 @@ internal class BlockGenerator(private val codegen: CodeGenerator) { invokeName: String, genBody: FunctionGenerationContext.(LLVMValueRef, List) -> Unit ): ConstPointer { - val result = generateFunction(codegen, blockType.blockInvokeLlvmType, invokeName, switchToRunnable = true) { + val result = functionGenerator(blockType.blockInvokeLlvmType, invokeName) { + switchToRunnable = true + }.generate { val blockPtr = bitcast(pointerType(blockLiteralType), param(0)) val kotlinObject = call( context.llvm.kRefSharedHolderRef, @@ -292,11 +292,10 @@ internal class BlockGenerator(private val codegen: CodeGenerator) { generateDescriptorForBlock(blockType) ) - return generateFunction( - codegen, + return functionGenerator( functionType(int8TypePtr, false, codegen.kObjHeaderPtr), convertName - ) { + ).generate { val kotlinRef = param(0) ifThen(icmpEq(kotlinRef, kNullObjHeaderPtr)) { ret(kNullInt8Ptr) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index 06cb042dd74..1860ccd5e6b 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -47,6 +47,35 @@ internal fun TypeBridge.makeNothing() = when (this) { is ValueTypeBridge -> LLVMConstNull(this.objCValueType.llvmType)!! } +internal class ObjCExportFunctionGenerationContext( + builder: ObjCExportFunctionGenerationContextBuilder +) : FunctionGenerationContext(builder) { + private val objCExportCodegen = builder.objCExportCodegen + +} + +internal class ObjCExportFunctionGenerationContextBuilder( + functionType: LLVMTypeRef, + functionName: String, + val objCExportCodegen: ObjCExportCodeGeneratorBase +) : FunctionGenerationContextBuilder( + functionType, + functionName, + objCExportCodegen.codegen +) { + override fun build() = ObjCExportFunctionGenerationContext(this) +} + +internal inline fun ObjCExportCodeGeneratorBase.functionGenerator( + functionType: LLVMTypeRef, + functionName: String, + configure: ObjCExportFunctionGenerationContextBuilder.() -> Unit = {} +): ObjCExportFunctionGenerationContextBuilder = ObjCExportFunctionGenerationContextBuilder( + functionType, + functionName, + this +).apply(configure) + internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCodeGenerator(codegen) { val symbols get() = context.ir.symbols val runtime get() = codegen.runtime @@ -637,7 +666,7 @@ private fun ObjCExportCodeGenerator.emitBoxConverter( val boxClass = boxClassSymbol.owner val name = "${boxClass.name}ToNSNumber" - val converter = generateFunction(codegen, kotlinToObjCFunctionType, name) { + val converter = functionGenerator(kotlinToObjCFunctionType, name).generate { val unboxFunction = context.getUnboxFunction(boxClass).llvmFunction val kotlinValue = callFromBridge( unboxFunction, @@ -760,25 +789,24 @@ private fun ObjCExportCodeGenerator.emitCollectionConverters() { ) } +private fun ObjCExportFunctionGenerationContextBuilder.setupBridgeDebugInfo() { + val location = setupBridgeDebugInfo(this.objCExportCodegen.context, function) + startLocation = location + endLocation = location +} + private inline fun ObjCExportCodeGenerator.generateObjCImpBy( methodBridge: MethodBridge, debugInfo: Boolean = false, genBody: FunctionGenerationContext.() -> Unit ): LLVMValueRef { - val result = addLlvmFunctionWithDefaultAttributes( - context, - context.llvmModule!!, - "objc2kotlin", - objCFunctionType(context, methodBridge) - ) + val result = functionGenerator(objCFunctionType(context, methodBridge), "objc2kotlin") { + if (debugInfo) { + this.setupBridgeDebugInfo() + } - val location = if (debugInfo) { - setupBridgeDebugInfo(context, result) - } else { - null - } - - generateFunction(codegen, result, startLocation = location, endLocation = location, switchToRunnable = true) { + switchToRunnable = true + }.generate { genBody() } @@ -1019,7 +1047,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge( val functionType = codegen.getLlvmFunctionType(irFunction) - val result = generateFunction(codegen, functionType, "kotlin2objc") { + val result = functionGenerator(functionType, "kotlin2objc").generate { var errorOutPtr: LLVMValueRef? = null val parameters = irFunction.allParameters.mapIndexed { index, parameterDescriptor -> @@ -1526,7 +1554,9 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter( MethodBridgeReceiver.Static, valueParameters = emptyList() ) - val imp = generateFunction(codegen, objCFunctionType(context, methodBridge), "objc2kotlin", switchToRunnable = true) { + val imp = functionGenerator(objCFunctionType(context, methodBridge), "objc2kotlin") { + switchToRunnable = true + }.generate { block() }