From d44b79fa51651f16fe266eaabfec3a6127b60b6b Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 29 Nov 2016 13:02:19 +0700 Subject: [PATCH] Review feedback, part 1 --- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 61 +++++++++++++------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index d1a212eebe8..25438c57517 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -546,7 +546,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid } /** - * Creates new [ContinuationBlock] and generates [code] starting from its' beginning. + * Creates new [ContinuationBlock] and generates [code] starting from its beginning. */ private inline fun continuationBlock(type: LLVMTypeRef, code: (LLVMValueRef) -> Unit): ContinuationBlock { val entry = codegen.basicBlock() @@ -559,7 +559,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid } /** - * Creates new [ContinuationBlock] that don't receive the value and generates [code] starting from its' beginning. + * Creates new [ContinuationBlock] that don't receive the value and generates [code] starting from its beginning. */ private inline fun continuationBlock(code: () -> Unit): ContinuationBlock { val block = codegen.basicBlock() @@ -573,7 +573,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid /** * Creates new [ContinuationBlock] that receives the value of type corresponding to given Kotlin type - * and generates [code] starting from its' beginning. + * and generates [code] starting from its beginning. */ private fun continuationBlock(type: KotlinType, code: (LLVMValueRef?) -> Unit = {}): ContinuationBlock { return if (type.isUnitOrNothing()) { @@ -618,7 +618,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid /** * The LLVM `landingpad` such that if invoked function throws an exception, - * then this exception is passed to [catch]. + * then this exception is passed to [handler]. */ private val landingpad: LLVMBasicBlockRef by lazy { using(outerContext) { @@ -630,9 +630,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid /** * The Kotlin exception handler, i.e. the [ContinuationBlock] which gets started - * when the exception is caught, receiving this exception as its' value. + * when the exception is caught, receiving this exception as its value. */ - private val catch by lazy { + private val handler by lazy { using(outerContext) { continuationBlock(kInt8Ptr) { exception -> genHandler(exception) @@ -641,34 +641,55 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid } private fun jumpToHandler(exception: LLVMValueRef) { - val catch = this.catch - jump(catch, exception) + jump(this.handler, exception) } /** * Generates the LLVM `landingpad` that catches C++ exception with type `KotlinException`, - * unwraps the Kotlin exception object and jumps to [catch]. + * unwraps the Kotlin exception object and jumps to [handler]. + * + * This method generates nearly the same code as `clang++` does for the following: + * ``` + * catch (KotlinException& e) { + * KRef exception = e.exception_; + * return exception; + * } + * ``` + * except that our code doesn't check exception `typeid`. + * + * TODO: why does `clang++` check `typeid` even if there is only one catch clause? */ private fun genLandingpad() { with(codegen) { - val lpType = structType(int8TypePtr, int32Type) - val persFn = externalFunction("__gxx_personality_v0", functionType(int32Type, true)) - val persFnRaw = LLVMConstBitCast(persFn, int8TypePtr)!! + // Type of `landingpad` instruction result (depends on personality function): + val landingpadType = structType(int8TypePtr, int32Type) - val lp = LLVMBuildLandingPad(codegen.builder, lpType, persFnRaw, 1, "lp") - LLVMAddClause(lp, externalGlobal("_ZTI15KotlinException", int8Type)) + val personalityFunction = externalFunction("__gxx_personality_v0", functionType(int32Type, true)) + val personalityFunctionRaw = LLVMConstBitCast(personalityFunction, int8TypePtr)!! + + val numClauses = 1 + val landingpadResult = + LLVMBuildLandingPad(codegen.builder, landingpadType, personalityFunctionRaw, numClauses, "lp") + + // Configure landingpad to catch C++ exception with type `KotlinException`: + LLVMAddClause(landingpadResult, externalGlobal("_ZTI15KotlinException", int8Type)) // FIXME: properly handle C++ exceptions: currently C++ exception can be thrown out from try-finally // bypassing the finally block. - val exceptionRecord = LLVMBuildExtractValue(codegen.builder, lp, 0, "er") + val exceptionRecord = LLVMBuildExtractValue(codegen.builder, landingpadResult, 0, "er") + // __cxa_begin_catch returns pointer to C++ exception object. val beginCatch = externalFunction("__cxa_begin_catch", functionType(int8TypePtr, false, int8TypePtr)) val exceptionRawPtr = call(beginCatch, listOf(exceptionRecord), "") + // Pointer to KotlinException instance: val exceptionPtr = bitcast(pointerType(int8TypePtr), exceptionRawPtr, "") + + // Pointer to Kotlin exception object: val exception = load(exceptionPtr, "exception") + // __cxa_end_catch performs some C++ cleanup, including calling `KotlinException` class destructor. val endCatch = externalFunction("__cxa_end_catch", functionType(voidType, false)) call(endCatch, listOf(), "") @@ -695,7 +716,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid * The [CatchingScope] that handles exceptions using Kotlin `catch` clauses. * * @param success the block to be used when the exception is successfully handled; - * expects `catch` expression result as its' value. + * expects `catch` expression result as its value. */ private inner class CatchScope(private val catches: List, private val success: ContinuationBlock) : CatchingScope() { @@ -728,7 +749,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid /** * The [ContinuationBlock] to be used for `return` from the function. - * Expects return value as its' value. + * Expects return value as its value. */ private val returnFromCurrent: ContinuationBlock by lazy { using(outerContext) { @@ -765,7 +786,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid * Generates the code which gets "finalized" exactly once when completed either normally or abnormally. * * @param code generates the code to be post-dominated by cleanup. - * It must jump to given [ContinuationBlock] with its' result when completed normally. + * It must jump to given [ContinuationBlock] with its result when completed normally. * * @param finalize generates the cleanup code that must be executed when code generated by [code] is completed. * @@ -815,9 +836,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid return genFinalizedBy(expression.finallyExpression, expression.type) { continuation -> - val catch = if (expression.catches.isEmpty()) null else CatchScope(expression.catches, continuation) + val catchScope = if (expression.catches.isEmpty()) null else CatchScope(expression.catches, continuation) - using(catch) { + using(catchScope) { evaluateExpressionAndJump(expression.tryResult, continuation) } }