Removed finally blocks handling from code generator

This commit is contained in:
Igor Chevdar
2017-05-03 13:41:42 +05:00
parent 3c84e39360
commit 667b5fb936
@@ -906,148 +906,24 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
}
}
/**
* The [InnerScope] that includes code generated by [genFinalizeImpl] when leaving it
* with `return`, `break`, `continue` or throwing exception.
*/
private abstract inner class FinalizingScope() : CatchingScope() {
/**
* Cache for [genReturn].
*
* `returnBlocks[func]` contains the [ContinuationBlock] to be used for `return` from `func`;
* the block expects return value as its value.
*/
private val returnBlocks = mutableMapOf<CallableDescriptor, ContinuationBlock>()
// Jump to finalize-and-return instead of simply returning.
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
val block = returnBlocks.getOrPut(target) {
continuationBlock(target.returnType!!) {
genFinalize()
val returnValue = it.valuePhi // `null` if return type is `Unit`.
outerContext.genReturn(target, returnValue)
}
}
jump(block, value)
}
/**
* Cache for [genBreak].
*/
private val breakBlocks = mutableMapOf<IrLoop, LLVMBasicBlockRef>()
// Jump to finalize-and-break instead of simply breaking.
override fun genBreak(destination: IrBreak) {
val block = breakBlocks.getOrPut(destination.loop) {
codegen.basicBlock("finalizeAndBreak") {
genFinalize()
outerContext.genBreak(destination)
}
}
codegen.br(block)
}
/**
* Cache for [genContinue].
*
* Note: can't merge with [breakBlocks] because the code for `break` and `continue` is different.
*/
private val continueBlocks = mutableMapOf<IrLoop, LLVMBasicBlockRef>()
// Jump to finalize-and-continue instead of simply continuing.
override fun genContinue(destination: IrContinue) {
val block = continueBlocks.getOrPut(destination.loop) {
codegen.basicBlock("finalizeAndContinue") {
genFinalize()
outerContext.genContinue(destination)
}
}
codegen.br(block)
}
// When an exception is caught, finalize the scope and rethrow the exception.
override fun genHandler(exception: LLVMValueRef) {
genFinalizeImpl()
outerContext.genThrow(exception)
}
private fun genFinalize() {
using(outerContext) {
this.genFinalizeImpl()
}
}
protected abstract fun genFinalizeImpl()
}
/**
* 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.
*
* @param finalize generates the cleanup code that must be executed when code generated by [code] is completed.
*
* @param type Kotlin type of the result of generated code.
*
* @return the result of the generated code.
*/
private fun genFinalizedBy(finalize: (() -> Unit)?,
type: KotlinType, code: (ContinuationBlock) -> Unit): LLVMValueRef {
val scope = if (finalize == null) null else {
object : FinalizingScope() {
override fun genFinalizeImpl() {
finalize()
}
}
}
val continuation = continuationBlock(type)
using(scope) {
code(continuation)
}
codegen.positionAtEnd(continuation.block)
finalize?.invoke()
// TODO: finalize is duplicated many times (just as in C++, Java or Kotlin JVM);
// it is very important to optimize this.
return continuation.value
}
/**
* Generates code that is "finalized" by given expression.
*/
private fun genFinalizedBy(finalize: IrExpression?, type: KotlinType,
code: (ContinuationBlock) -> Unit): LLVMValueRef {
val finalizeFun: (() -> Unit)? = if (finalize == null) {
null
} else {
{ evaluateExpression(finalize) }
}
return genFinalizedBy(finalizeFun, type, code)
}
private fun evaluateTry(expression: IrTry): LLVMValueRef {
// TODO: does basic block order influence machine code order?
// If so, consider reordering blocks to reduce exception tables size.
return genFinalizedBy(expression.finallyExpression, expression.type) { continuation ->
assert (expression.finallyExpression == null, { "All finally blocks should've been lowered" })
val catchScope = if (expression.catches.isEmpty()) null else CatchScope(expression.catches, continuation)
val continuation = continuationBlock(expression.type)
using(catchScope) {
evaluateExpressionAndJump(expression.tryResult, continuation)
}
val catchScope = if (expression.catches.isEmpty())
null
else
CatchScope(expression.catches, continuation)
using(catchScope) {
evaluateExpressionAndJump(expression.tryResult, continuation)
}
codegen.positionAtEnd(continuation.block)
return continuation.value
}
//-------------------------------------------------------------------------//