Apply minor refactoring to exception handling

This commit is contained in:
Svyatoslav Scherbina
2018-01-09 12:36:39 +03:00
committed by SvyatoslavScherbina
parent b700f96e0c
commit d4f39f8142
4 changed files with 39 additions and 33 deletions
@@ -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)
}
@@ -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
}
@@ -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
@@ -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(