Review feedback, part 1

This commit is contained in:
Svyatoslav Scherbina
2016-11-29 13:02:19 +07:00
parent 9848091186
commit d44b79fa51
@@ -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 { private inline fun continuationBlock(type: LLVMTypeRef, code: (LLVMValueRef) -> Unit): ContinuationBlock {
val entry = codegen.basicBlock() 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 { private inline fun continuationBlock(code: () -> Unit): ContinuationBlock {
val block = codegen.basicBlock() 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 * 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 { private fun continuationBlock(type: KotlinType, code: (LLVMValueRef?) -> Unit = {}): ContinuationBlock {
return if (type.isUnitOrNothing()) { 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, * 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 { private val landingpad: LLVMBasicBlockRef by lazy {
using(outerContext) { using(outerContext) {
@@ -630,9 +630,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
/** /**
* The Kotlin exception handler, i.e. the [ContinuationBlock] which gets started * 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) { using(outerContext) {
continuationBlock(kInt8Ptr) { exception -> continuationBlock(kInt8Ptr) { exception ->
genHandler(exception) genHandler(exception)
@@ -641,34 +641,55 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
} }
private fun jumpToHandler(exception: LLVMValueRef) { private fun jumpToHandler(exception: LLVMValueRef) {
val catch = this.catch jump(this.handler, exception)
jump(catch, exception)
} }
/** /**
* Generates the LLVM `landingpad` that catches C++ exception with type `KotlinException`, * 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() { private fun genLandingpad() {
with(codegen) { with(codegen) {
val lpType = structType(int8TypePtr, int32Type) // Type of `landingpad` instruction result (depends on personality function):
val persFn = externalFunction("__gxx_personality_v0", functionType(int32Type, true)) val landingpadType = structType(int8TypePtr, int32Type)
val persFnRaw = LLVMConstBitCast(persFn, int8TypePtr)!!
val lp = LLVMBuildLandingPad(codegen.builder, lpType, persFnRaw, 1, "lp") val personalityFunction = externalFunction("__gxx_personality_v0", functionType(int32Type, true))
LLVMAddClause(lp, externalGlobal("_ZTI15KotlinException", int8Type)) 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 // 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, 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 beginCatch = externalFunction("__cxa_begin_catch", functionType(int8TypePtr, false, int8TypePtr))
val exceptionRawPtr = call(beginCatch, listOf(exceptionRecord), "") val exceptionRawPtr = call(beginCatch, listOf(exceptionRecord), "")
// Pointer to KotlinException instance:
val exceptionPtr = bitcast(pointerType(int8TypePtr), exceptionRawPtr, "") val exceptionPtr = bitcast(pointerType(int8TypePtr), exceptionRawPtr, "")
// Pointer to Kotlin exception object:
val exception = load(exceptionPtr, "exception") 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)) val endCatch = externalFunction("__cxa_end_catch", functionType(voidType, false))
call(endCatch, listOf(), "") call(endCatch, listOf(), "")
@@ -695,7 +716,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
* The [CatchingScope] that handles exceptions using Kotlin `catch` clauses. * The [CatchingScope] that handles exceptions using Kotlin `catch` clauses.
* *
* @param success the block to be used when the exception is successfully handled; * @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<IrCatch>, private inner class CatchScope(private val catches: List<IrCatch>,
private val success: ContinuationBlock) : CatchingScope() { 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. * 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 { private val returnFromCurrent: ContinuationBlock by lazy {
using(outerContext) { 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. * 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. * @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. * @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 -> 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) evaluateExpressionAndJump(expression.tryResult, continuation)
} }
} }