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 numParams = LLVMCountParams(llvmFunction)
|
||||||
val args = (0 .. numParams - 1).map { index -> param(index) }
|
val args = (0 .. numParams - 1).map { index -> param(index) }
|
||||||
val callee = lookupVirtualImpl(receiver, function)
|
val callee = lookupVirtualImpl(receiver, function)
|
||||||
val result = callAtFunctionScopeVerbatim(callee, args)
|
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
|
||||||
ret(result)
|
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
|
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?
|
val LLVMValueRef.name:String?
|
||||||
get() = LLVMGetValueName(this)?.toKString()
|
get() = LLVMGetValueName(this)?.toKString()
|
||||||
|
|
||||||
@@ -132,6 +140,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
private val epilogueBb = basicBlockInFunction("epilogue", endLocation)
|
private val epilogueBb = basicBlockInFunction("epilogue", endLocation)
|
||||||
private val cleanupLandingpad = basicBlockInFunction("cleanup_landingpad", endLocation)
|
private val cleanupLandingpad = basicBlockInFunction("cleanup_landingpad", endLocation)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: consider merging this with [ExceptionHandler].
|
||||||
|
*/
|
||||||
var forwardingForeignExceptionsTerminatedWith: LLVMValueRef? = null
|
var forwardingForeignExceptionsTerminatedWith: LLVMValueRef? = null
|
||||||
|
|
||||||
init {
|
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>,
|
fun call(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
|
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
|
||||||
lazyLandingpad: () -> LLVMBasicBlockRef? = { null },
|
exceptionHandler: ExceptionHandler = ExceptionHandler.None,
|
||||||
verbatim: Boolean = false): LLVMValueRef {
|
verbatim: Boolean = false): LLVMValueRef {
|
||||||
val callArgs = if (verbatim || !isObjectReturn(llvmFunction.type)) {
|
val callArgs = if (verbatim || !isObjectReturn(llvmFunction.type)) {
|
||||||
args
|
args
|
||||||
@@ -291,30 +294,34 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
}
|
}
|
||||||
args + resultSlot
|
args + resultSlot
|
||||||
}
|
}
|
||||||
return callRaw(llvmFunction, callArgs, lazyLandingpad)
|
return callRaw(llvmFunction, callArgs, exceptionHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun callRaw(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
private fun callRaw(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||||
lazyLandingpad: () -> LLVMBasicBlockRef?): LLVMValueRef {
|
exceptionHandler: ExceptionHandler): LLVMValueRef {
|
||||||
val rargs = args.toCValues()
|
val rargs = args.toCValues()
|
||||||
if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ &&
|
if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ &&
|
||||||
isFunctionNoUnwind(llvmFunction)) {
|
isFunctionNoUnwind(llvmFunction)) {
|
||||||
|
|
||||||
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!!
|
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!!
|
||||||
} else {
|
} else {
|
||||||
val landingpad = lazyLandingpad()
|
val unwind = when (exceptionHandler) {
|
||||||
|
ExceptionHandler.Caller -> cleanupLandingpad
|
||||||
|
is ExceptionHandler.Local -> exceptionHandler.unwind
|
||||||
|
|
||||||
if (landingpad == null) {
|
ExceptionHandler.None -> {
|
||||||
// When calling a function that is not marked as nounwind (can throw an exception),
|
// 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.
|
// it is required to specify an unwind label to handle exceptions properly.
|
||||||
// Runtime C++ function can be marked as non-throwing using `RUNTIME_NOTHROW`.
|
// Runtime C++ function can be marked as non-throwing using `RUNTIME_NOTHROW`.
|
||||||
val functionName = llvmFunction.name
|
val functionName = llvmFunction.name
|
||||||
val message = "no landingpad specified when calling function $functionName without nounwind attr"
|
val message =
|
||||||
throw IllegalArgumentException(message)
|
"no exception handler specified when calling function $functionName without nounwind attr"
|
||||||
|
throw IllegalArgumentException(message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val success = basicBlock("call_success", position())
|
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)
|
positionAtEnd(success)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-11
@@ -165,7 +165,7 @@ internal interface CodeContext {
|
|||||||
|
|
||||||
fun genContinue(destination: IrContinue)
|
fun genContinue(destination: IrContinue)
|
||||||
|
|
||||||
fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef
|
val exceptionHandler: ExceptionHandler
|
||||||
|
|
||||||
fun genThrow(exception: LLVMValueRef)
|
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 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()
|
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) =
|
override val exceptionHandler get() = ExceptionHandler.Caller
|
||||||
functionGenerationContext.callAtFunctionScope(function, args, resultLifetime)
|
|
||||||
|
|
||||||
override fun genThrow(exception: LLVMValueRef) {
|
override fun genThrow(exception: LLVMValueRef) {
|
||||||
val objHeaderPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, exception)
|
val objHeaderPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, exception)
|
||||||
val args = listOf(objHeaderPtr)
|
val args = listOf(objHeaderPtr)
|
||||||
|
|
||||||
this.genCall(context.llvm.throwExceptionFunction, args, Lifetime.IRRELEVANT)
|
functionGenerationContext.call(
|
||||||
|
context.llvm.throwExceptionFunction, args, Lifetime.IRRELEVANT, this.exceptionHandler
|
||||||
|
)
|
||||||
functionGenerationContext.unreachable()
|
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 val exceptionHandler: ExceptionHandler get() = object : ExceptionHandler.Local() {
|
||||||
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef {
|
override val unwind get() = landingpad
|
||||||
val res = functionGenerationContext.call(function, args, resultLifetime, this::landingpad)
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun genThrow(exception: LLVMValueRef) {
|
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>,
|
private fun call(function: LLVMValueRef, args: List<LLVMValueRef>,
|
||||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT): 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
|
// launcher, so we could optimize out creating slot for 'parameter' in
|
||||||
// this function.
|
// this function.
|
||||||
val parameter = LLVMGetParam(selector, 0)!!
|
val parameter = LLVMGetParam(selector, 0)!!
|
||||||
callAtFunctionScope(entryPoint, listOf(parameter), Lifetime.IRRELEVANT)
|
call(entryPoint, listOf(parameter), Lifetime.IRRELEVANT, ExceptionHandler.Caller)
|
||||||
ret(null)
|
ret(null)
|
||||||
}
|
}
|
||||||
return selector
|
return selector
|
||||||
|
|||||||
+1
-1
@@ -65,7 +65,7 @@ internal class ObjCExportCodeGenerator(
|
|||||||
// TODO: it is required only for Kotlin-to-Objective-C bridges.
|
// TODO: it is required only for Kotlin-to-Objective-C bridges.
|
||||||
this.forwardingForeignExceptionsTerminatedWith = objcTerminate
|
this.forwardingForeignExceptionsTerminatedWith = objcTerminate
|
||||||
|
|
||||||
return callAtFunctionScope(function, args, resultLifetime)
|
return call(function, args, resultLifetime, ExceptionHandler.Caller)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FunctionGenerationContext.genSendMessage(
|
fun FunctionGenerationContext.genSendMessage(
|
||||||
|
|||||||
Reference in New Issue
Block a user