Apply minor refactoring to exception handling
This commit is contained in:
committed by
SvyatoslavScherbina
parent
b700f96e0c
commit
d4f39f8142
+1
-1
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+27
-20
@@ -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<LLVMValueRef>,
|
||||
lifetime: Lifetime) =
|
||||
call(llvmFunction, args, lifetime, { cleanupLandingpad })
|
||||
|
||||
|
||||
fun callAtFunctionScopeVerbatim(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>) =
|
||||
call(llvmFunction, args, Lifetime.IRRELEVANT, { cleanupLandingpad }, true)
|
||||
|
||||
fun call(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
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<LLVMValueRef>,
|
||||
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
|
||||
}
|
||||
|
||||
+10
-11
@@ -165,7 +165,7 @@ internal interface CodeContext {
|
||||
|
||||
fun genContinue(destination: IrContinue)
|
||||
|
||||
fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef
|
||||
val exceptionHandler: ExceptionHandler
|
||||
|
||||
fun genThrow(exception: LLVMValueRef)
|
||||
|
||||
@@ -237,7 +237,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
override fun genContinue(destination: IrContinue) = unsupported()
|
||||
|
||||
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, 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<IrE
|
||||
}
|
||||
}
|
||||
|
||||
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, 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<IrE
|
||||
}
|
||||
}
|
||||
|
||||
// The call inside [CatchingScope] must be configured to dispatch exception to the scope's handler.
|
||||
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, 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<IrE
|
||||
|
||||
private fun call(function: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
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<IrE
|
||||
// launcher, so we could optimize out creating slot for 'parameter' in
|
||||
// this function.
|
||||
val parameter = LLVMGetParam(selector, 0)!!
|
||||
callAtFunctionScope(entryPoint, listOf(parameter), Lifetime.IRRELEVANT)
|
||||
call(entryPoint, listOf(parameter), Lifetime.IRRELEVANT, ExceptionHandler.Caller)
|
||||
ret(null)
|
||||
}
|
||||
return selector
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ internal class ObjCExportCodeGenerator(
|
||||
// TODO: it is required only for Kotlin-to-Objective-C bridges.
|
||||
this.forwardingForeignExceptionsTerminatedWith = objcTerminate
|
||||
|
||||
return callAtFunctionScope(function, args, resultLifetime)
|
||||
return call(function, args, resultLifetime, ExceptionHandler.Caller)
|
||||
}
|
||||
|
||||
fun FunctionGenerationContext.genSendMessage(
|
||||
|
||||
Reference in New Issue
Block a user