Native: minor exception handling refactoring

Move parts of exception handling implementation from IrToBitcode
to CodeGenerator, to allow using filteringExceptionHandler in ObjCExport.
This commit is contained in:
Svyatoslav Scherbina
2021-05-20 10:39:06 +03:00
committed by Space
parent 2801704ad3
commit 388538be60
2 changed files with 43 additions and 34 deletions
@@ -95,6 +95,19 @@ internal sealed class ExceptionHandler {
abstract class Local : ExceptionHandler() {
abstract val unwind: LLVMBasicBlockRef
}
open fun genThrow(
functionGenerationContext: FunctionGenerationContext,
kotlinException: LLVMValueRef
): Unit = with(functionGenerationContext) {
call(
context.llvm.throwExceptionFunction,
listOf(kotlinException),
Lifetime.IRRELEVANT,
this@ExceptionHandler
)
unreachable()
}
}
internal enum class ThreadState {
@@ -790,7 +803,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
return LLVMBuildExtractElement(builder, vector, index, name)!!
}
fun filteringExceptionHandler(codeContext: CodeContext, foreignExceptionMode: ForeignExceptionMode.Mode, switchThreadState: Boolean): ExceptionHandler {
fun filteringExceptionHandler(
outerHandler: ExceptionHandler,
foreignExceptionMode: ForeignExceptionMode.Mode,
switchThreadState: Boolean
): ExceptionHandler {
val lpBlock = basicBlockInFunction("filteringExceptionHandler", position()?.start)
val wrapExceptionMode = context.config.target.family.isAppleFamily &&
@@ -830,8 +847,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
condBr(isObjCException, forwardNativeExceptionBlock, fatalForeignExceptionBlock)
appendingTo(forwardNativeExceptionBlock) {
val exception = createForeignException(landingpad, codeContext.exceptionHandler)
codeContext.genThrow(exception)
val exception = createForeignException(landingpad, outerHandler)
outerHandler.genThrow(this, exception)
}
}
} else {
@@ -840,7 +857,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
appendingTo(forwardKotlinExceptionBlock) {
// Rethrow Kotlin exception to real handler.
codeContext.genThrow(extractKotlinException(landingpad))
outerHandler.genThrow(this, extractKotlinException(landingpad))
}
appendingTo(fatalForeignExceptionBlock) {
@@ -106,7 +106,7 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
/**
* Defines how to generate context-dependent operations.
*/
internal interface CodeContext {
private interface CodeContext {
/**
* Generates `return` [value] operation.
@@ -121,8 +121,6 @@ internal interface CodeContext {
val exceptionHandler: ExceptionHandler
fun genThrow(exception: LLVMValueRef)
val stackLocalsManager: StackLocalsManager
/**
@@ -240,8 +238,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override val exceptionHandler get() = unsupported()
override fun genThrow(exception: LLVMValueRef) = unsupported()
override val stackLocalsManager: StackLocalsManager get() = unsupported()
override fun genDeclareVariable(variable: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?) = unsupported(variable)
@@ -677,16 +673,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override val exceptionHandler: ExceptionHandler
get() = ExceptionHandler.Caller
override fun genThrow(exception: LLVMValueRef) {
val objHeaderPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, exception)
val args = listOf(objHeaderPtr)
functionGenerationContext.call(
context.llvm.throwExceptionFunction, args, Lifetime.IRRELEVANT, this.exceptionHandler
)
functionGenerationContext.unreachable()
}
override val stackLocalsManager get() = functionGenerationContext.stackLocalsManager
override fun functionScope(): CodeContext = this
@@ -942,7 +928,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// however such optimization can lead to phi functions with zero entries, which is not allowed by LLVM;
// TODO: find the better solution.
jump(destination, result)
functionGenerationContext.jump(destination, result)
}
//-------------------------------------------------------------------------//
@@ -964,11 +950,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
/**
* Jumps to [target] passing [value].
*/
private fun jump(target: ContinuationBlock, value: LLVMValueRef?) {
private fun FunctionGenerationContext.jump(target: ContinuationBlock, value: LLVMValueRef?) {
val entry = target.block
functionGenerationContext.br(entry)
br(entry)
if (target.valuePhi != null) {
functionGenerationContext.assignPhis(target.valuePhi to value!!)
assignPhis(target.valuePhi to value!!)
}
}
@@ -1020,7 +1006,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateThrow(expression: IrThrow): LLVMValueRef {
val exception = evaluateExpression(expression.value)
currentCodeContext.genThrow(exception)
currentCodeContext.exceptionHandler.genThrow(functionGenerationContext, exception)
return codegen.kNothingFakeValue
}
@@ -1063,8 +1049,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return irFunction?.endLocation
}
private fun jumpToHandler(exception: LLVMValueRef) {
jump(this.handler, exception)
private fun FunctionGenerationContext.jumpToHandler(exception: LLVMValueRef) {
jump(handler, exception)
}
/**
@@ -1092,11 +1078,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override val exceptionHandler: ExceptionHandler
get() = object : ExceptionHandler.Local() {
override val unwind get() = landingpad
}
override fun genThrow(exception: LLVMValueRef) {
jumpToHandler(exception)
}
override fun genThrow(functionGenerationContext: FunctionGenerationContext, kotlinException: LLVMValueRef) {
// Super class implementation would do too, so this is just an optimization:
// use local jump instead of wrapping to C++ exception, throwing, catching and unwrapping it:
functionGenerationContext.jumpToHandler(kotlinException)
}
}
protected abstract fun genHandler(exception: LLVMValueRef)
}
@@ -1137,7 +1125,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
// rethrow the exception if no clause can handle it.
outerContext.genThrow(exception)
outerContext.exceptionHandler.genThrow(functionGenerationContext, exception)
}
}
@@ -2148,11 +2136,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
using (SuspensionPointScope(expression.suspensionPointIdParameter, bbResume, id)) {
continuationBlock(expression.type, expression.result.startLocation).run {
val normalResult = evaluateExpression(expression.result)
jump(this, normalResult)
functionGenerationContext.jump(this, normalResult)
functionGenerationContext.positionAtEnd(bbResume)
val resumeResult = evaluateExpression(expression.resumeResult)
jump(this, resumeResult)
functionGenerationContext.jump(this, resumeResult)
functionGenerationContext.positionAtEnd(this.block)
return this.value
@@ -2354,7 +2342,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val needsNativeThreadState = function.needsNativeThreadState
val exceptionHandler = function.annotations.findAnnotation(RuntimeNames.filterExceptions)?.let {
val foreignExceptionMode = ForeignExceptionMode.byValue(it.getAnnotationValueOrNull<String>("mode"))
functionGenerationContext.filteringExceptionHandler(currentCodeContext, foreignExceptionMode, needsNativeThreadState)
functionGenerationContext.filteringExceptionHandler(
currentCodeContext.exceptionHandler,
foreignExceptionMode,
needsNativeThreadState
)
} ?: currentCodeContext.exceptionHandler
if (needsNativeThreadState) {