diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt index 0e143dd968f..bd7c4436d7e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt @@ -180,7 +180,7 @@ private class ExportedElement(val kind: ElementKind, val numParams = LLVMCountParams(llvmFunction) val args = (0 .. numParams - 1).map { index -> param(index) } val callee = lookupVirtualImpl(receiver, function) - val result = callAtFunctionScopeVerbatim(callee, args) + val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true) ret(result) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index d3c1d102166..b88f56123b5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -51,6 +51,14 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun functionHash(descriptor: FunctionDescriptor): LLVMValueRef = descriptor.functionName.localHash.llvm } +internal sealed class ExceptionHandler { + object None : ExceptionHandler() + object Caller : ExceptionHandler() + abstract class Local : ExceptionHandler() { + abstract val unwind: LLVMBasicBlockRef + } +} + val LLVMValueRef.name:String? get() = LLVMGetValueName(this)?.toKString() @@ -132,6 +140,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, private val epilogueBb = basicBlockInFunction("epilogue", endLocation) private val cleanupLandingpad = basicBlockInFunction("cleanup_landingpad", endLocation) + /** + * TODO: consider merging this with [ExceptionHandler]. + */ var forwardingForeignExceptionsTerminatedWith: LLVMValueRef? = null init { @@ -241,17 +252,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, //-------------------------------------------------------------------------// - fun callAtFunctionScope(llvmFunction: LLVMValueRef, args: List, - lifetime: Lifetime) = - call(llvmFunction, args, lifetime, { cleanupLandingpad }) - - - fun callAtFunctionScopeVerbatim(llvmFunction: LLVMValueRef, args: List) = - call(llvmFunction, args, Lifetime.IRRELEVANT, { cleanupLandingpad }, true) - fun call(llvmFunction: LLVMValueRef, args: List, resultLifetime: Lifetime = Lifetime.IRRELEVANT, - lazyLandingpad: () -> LLVMBasicBlockRef? = { null }, + exceptionHandler: ExceptionHandler = ExceptionHandler.None, verbatim: Boolean = false): LLVMValueRef { val callArgs = if (verbatim || !isObjectReturn(llvmFunction.type)) { args @@ -291,30 +294,34 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, } args + resultSlot } - return callRaw(llvmFunction, callArgs, lazyLandingpad) + return callRaw(llvmFunction, callArgs, exceptionHandler) } private fun callRaw(llvmFunction: LLVMValueRef, args: List, - lazyLandingpad: () -> LLVMBasicBlockRef?): LLVMValueRef { + exceptionHandler: ExceptionHandler): LLVMValueRef { val rargs = args.toCValues() if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ && isFunctionNoUnwind(llvmFunction)) { return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!! } else { - val landingpad = lazyLandingpad() + val unwind = when (exceptionHandler) { + ExceptionHandler.Caller -> cleanupLandingpad + is ExceptionHandler.Local -> exceptionHandler.unwind - if (landingpad == null) { - // When calling a function that is not marked as nounwind (can throw an exception), - // it is required to specify a landingpad to handle exceptions properly. - // Runtime C++ function can be marked as non-throwing using `RUNTIME_NOTHROW`. - val functionName = llvmFunction.name - val message = "no landingpad specified when calling function $functionName without nounwind attr" - throw IllegalArgumentException(message) + ExceptionHandler.None -> { + // When calling a function that is not marked as nounwind (can throw an exception), + // it is required to specify an unwind label to handle exceptions properly. + // Runtime C++ function can be marked as non-throwing using `RUNTIME_NOTHROW`. + val functionName = llvmFunction.name + val message = + "no exception handler specified when calling function $functionName without nounwind attr" + throw IllegalArgumentException(message) + } } val success = basicBlock("call_success", position()) - val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, landingpad, "")!! + val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, unwind, "")!! positionAtEnd(success) return result } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 5a9c52afed3..2bde873ecac 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -165,7 +165,7 @@ internal interface CodeContext { fun genContinue(destination: IrContinue) - fun genCall(function: LLVMValueRef, args: List, resultLifetime: Lifetime): LLVMValueRef + val exceptionHandler: ExceptionHandler fun genThrow(exception: LLVMValueRef) @@ -237,7 +237,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map, resultLifetime: Lifetime) = unsupported(function) + override val exceptionHandler get() = unsupported() override fun genThrow(exception: LLVMValueRef) = unsupported() @@ -558,14 +558,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map, resultLifetime: Lifetime) = - functionGenerationContext.callAtFunctionScope(function, args, resultLifetime) + override val exceptionHandler get() = ExceptionHandler.Caller override fun genThrow(exception: LLVMValueRef) { val objHeaderPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, exception) val args = listOf(objHeaderPtr) - this.genCall(context.llvm.throwExceptionFunction, args, Lifetime.IRRELEVANT) + functionGenerationContext.call( + context.llvm.throwExceptionFunction, args, Lifetime.IRRELEVANT, this.exceptionHandler + ) functionGenerationContext.unreachable() } @@ -938,10 +939,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map, resultLifetime: Lifetime): LLVMValueRef { - val res = functionGenerationContext.call(function, args, resultLifetime, this::landingpad) - return res + override val exceptionHandler: ExceptionHandler get() = object : ExceptionHandler.Local() { + override val unwind get() = landingpad } override fun genThrow(exception: LLVMValueRef) { @@ -2363,7 +2362,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map, resultLifetime: Lifetime = Lifetime.IRRELEVANT): LLVMValueRef { - return currentCodeContext.genCall(function, args, resultLifetime) + return functionGenerationContext.call(function, args, resultLifetime, currentCodeContext.exceptionHandler) } //-------------------------------------------------------------------------// @@ -2420,7 +2419,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map