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 {
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<IrCatch>,
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)
}
}