backend: perform cleanup if leaving the frame with exception
Also unify `call` & `invoke`, allow `call` without landingpad only if target function is nounwind
This commit is contained in:
committed by
SvyatoslavScherbina
parent
d389897631
commit
4cfe569001
+27
-11
@@ -105,7 +105,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
fun releaseVars() {
|
fun releaseVars() {
|
||||||
if (slotCount > 0) {
|
if (slotCount > 0) {
|
||||||
call(context.llvm.releaseLocalRefsFunction,
|
call(context.llvm.releaseLocalRefsFunction,
|
||||||
listOf(slotsPhi, Int32(slotCount).llvm))
|
listOf(slotsPhi!!, Int32(slotCount).llvm))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +115,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
private var cleanupLandingpad: LLVMBasicBlockRef? = null
|
private var cleanupLandingpad: LLVMBasicBlockRef? = null
|
||||||
|
|
||||||
fun setName(value: LLVMValueRef, name: String) = LLVMSetValueName(value, name)
|
fun setName(value: LLVMValueRef, name: String) = LLVMSetValueName(value, name)
|
||||||
|
fun getName(value: LLVMValueRef) = LLVMGetValueName(value)?.asCString().toString()
|
||||||
|
|
||||||
fun plus (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildAdd (builder, arg0, arg1, name)!!
|
fun plus (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildAdd (builder, arg0, arg1, name)!!
|
||||||
fun mul (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildMul (builder, arg0, arg1, name)!!
|
fun mul (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildMul (builder, arg0, arg1, name)!!
|
||||||
@@ -203,21 +204,36 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun invoke(llvmFunction: LLVMValueRef?, args: List<LLVMValueRef?>,
|
fun callAtFunctionScope(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>, name: String = "") =
|
||||||
then: LLVMBasicBlockRef, landingpad: LLVMBasicBlockRef,
|
call(llvmFunction, args, this::cleanupLandingpad, name)
|
||||||
name: String = ""): LLVMValueRef {
|
|
||||||
|
fun call(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||||
|
lazyLandingpad: () -> LLVMBasicBlockRef? = { null }, name: String = ""): LLVMValueRef {
|
||||||
|
|
||||||
memScoped {
|
memScoped {
|
||||||
val rargs = allocArrayOf(args)[0].ptr
|
val rargs = allocArrayOf(args)[0].ptr
|
||||||
return LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, then, landingpad, name)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ &&
|
||||||
|
LLVMAttribute.LLVMNoUnwindAttribute in LLVMGetFunctionAttrSet(llvmFunction)) {
|
||||||
|
|
||||||
fun call(llvmFunction: LLVMValueRef?, args: List<LLVMValueRef?>, name: String = ""): LLVMValueRef {
|
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, name)!!
|
||||||
memScoped {
|
} else {
|
||||||
val rargs = allocArrayOf(args)[0].ptr
|
val landingpad = lazyLandingpad()
|
||||||
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, name)!!
|
|
||||||
|
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 = getName(llvmFunction)
|
||||||
|
val message = "no landingpad specified when calling function $functionName without nounwind attr"
|
||||||
|
throw IllegalArgumentException(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
val success = basicBlock()
|
||||||
|
val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, landingpad, name)!!
|
||||||
|
positionAtEnd(success)
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -281,7 +281,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function.
|
val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function.
|
||||||
codegen.prologue(ctorFunction, voidType)
|
codegen.prologue(ctorFunction, voidType)
|
||||||
val initNodePtr = LLVMGetNamedGlobal(context.llvmModule, nodeName)!! // Get LLVM function initializing globals of current file.
|
val initNodePtr = LLVMGetNamedGlobal(context.llvmModule, nodeName)!! // Get LLVM function initializing globals of current file.
|
||||||
codegen.call(context.llvm.appendToInitalizersTail, initNodePtr.singletonList(), "") // Add node to the tail of initializers list.
|
codegen.call(context.llvm.appendToInitalizersTail, initNodePtr.singletonList()) // Add node to the tail of initializers list.
|
||||||
codegen.ret(null)
|
codegen.ret(null)
|
||||||
codegen.epilogue()
|
codegen.epilogue()
|
||||||
|
|
||||||
@@ -527,12 +527,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>) = codegen.call(function, args)
|
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>) =
|
||||||
|
codegen.callAtFunctionScope(function, args)
|
||||||
|
|
||||||
override fun genThrow(exception: LLVMValueRef) {
|
override fun genThrow(exception: LLVMValueRef) {
|
||||||
val objHeaderPtr = codegen.bitcast(codegen.kObjHeaderPtr, exception)
|
val objHeaderPtr = codegen.bitcast(codegen.kObjHeaderPtr, exception)
|
||||||
val args = listOf(objHeaderPtr)
|
val args = listOf(objHeaderPtr)
|
||||||
codegen.call(context.llvm.throwExceptionFunction, args, "")
|
|
||||||
|
this.genCall(context.llvm.throwExceptionFunction, args)
|
||||||
codegen.unreachable()
|
codegen.unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,12 +683,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
val ctor = codegen.llvmFunction(initFunction)
|
val ctor = codegen.llvmFunction(initFunction)
|
||||||
val args = listOf(objectPtr, typeInfo, allocHint, ctor)
|
val args = listOf(objectPtr, typeInfo, allocHint, ctor)
|
||||||
val newValue = call(context.llvm.initInstanceFunction, args)
|
val newValue = call(context.llvm.initInstanceFunction, args)
|
||||||
|
val bbInitResult = codegen.currentBlock
|
||||||
codegen.br(bbExit)
|
codegen.br(bbExit)
|
||||||
|
|
||||||
codegen.positionAtEnd(bbExit)
|
codegen.positionAtEnd(bbExit)
|
||||||
val valuePhi = codegen.phi(codegen.getLLVMType(value.type))
|
val valuePhi = codegen.phi(codegen.getLLVMType(value.type))
|
||||||
codegen.addPhiIncoming(valuePhi,
|
codegen.addPhiIncoming(valuePhi,
|
||||||
bbCurrent to objectVal, bbInit to newValue)
|
bbCurrent to objectVal, bbInitResult to newValue)
|
||||||
|
|
||||||
return valuePhi
|
return valuePhi
|
||||||
}
|
}
|
||||||
@@ -920,11 +923,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
// FIXME: properly handle C++ exceptions: currently C++ exception can be thrown out from try-finally
|
// FIXME: properly handle C++ exceptions: currently C++ exception can be thrown out from try-finally
|
||||||
// bypassing the finally block.
|
// bypassing the finally block.
|
||||||
|
|
||||||
val exceptionRecord = LLVMBuildExtractValue(codegen.builder, landingpadResult, 0, "er")
|
val exceptionRecord = LLVMBuildExtractValue(codegen.builder, landingpadResult, 0, "er")!!
|
||||||
|
|
||||||
// __cxa_begin_catch returns pointer to C++ exception object.
|
// __cxa_begin_catch returns pointer to C++ exception object.
|
||||||
val beginCatch = context.llvm.cxaBeginCatchFunction
|
val beginCatch = context.llvm.cxaBeginCatchFunction
|
||||||
val exceptionRawPtr = call(beginCatch, listOf(exceptionRecord), "")
|
val exceptionRawPtr = call(beginCatch, listOf(exceptionRecord))
|
||||||
|
|
||||||
// Pointer to KotlinException instance:
|
// Pointer to KotlinException instance:
|
||||||
val exceptionPtrPtr = bitcast(codegen.kObjHeaderPtrPtr, exceptionRawPtr, "")
|
val exceptionPtrPtr = bitcast(codegen.kObjHeaderPtrPtr, exceptionRawPtr, "")
|
||||||
@@ -935,7 +938,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
// __cxa_end_catch performs some C++ cleanup, including calling `KotlinException` class destructor.
|
// __cxa_end_catch performs some C++ cleanup, including calling `KotlinException` class destructor.
|
||||||
val endCatch = context.llvm.cxaEndCatchFunction
|
val endCatch = context.llvm.cxaEndCatchFunction
|
||||||
call(endCatch, listOf(), "")
|
call(endCatch, listOf())
|
||||||
|
|
||||||
jumpToHandler(exceptionPtr)
|
jumpToHandler(exceptionPtr)
|
||||||
}
|
}
|
||||||
@@ -943,11 +946,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
// The call inside [CatchingScope] must be configured to dispatch exception to the scope's handler.
|
// The call inside [CatchingScope] must be configured to dispatch exception to the scope's handler.
|
||||||
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>): LLVMValueRef {
|
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>): LLVMValueRef {
|
||||||
val landingpad = this.landingpad
|
val res = codegen.call(function, args, this::landingpad)
|
||||||
val then = codegen.basicBlock()
|
|
||||||
|
|
||||||
val res = codegen.invoke(function, args, then, landingpad)
|
|
||||||
codegen.positionAtEnd(then)
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1305,10 +1304,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
codegen.positionAtEnd(bbInstanceOf)
|
codegen.positionAtEnd(bbInstanceOf)
|
||||||
val resultInstanceOf = genInstanceOf(srcArg, type)
|
val resultInstanceOf = genInstanceOf(srcArg, type)
|
||||||
codegen.br(bbExit)
|
codegen.br(bbExit)
|
||||||
|
val bbInstanceOfResult = codegen.currentBlock
|
||||||
|
|
||||||
codegen.positionAtEnd(bbExit)
|
codegen.positionAtEnd(bbExit)
|
||||||
val result = codegen.phi(kBoolean)
|
val result = codegen.phi(kBoolean)
|
||||||
codegen.addPhiIncoming(result, bbNull to resultNull, bbInstanceOf to resultInstanceOf)
|
codegen.addPhiIncoming(result, bbNull to resultNull, bbInstanceOfResult to resultInstanceOf)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user