Removed finally blocks handling from code generator
This commit is contained in:
+11
-135
@@ -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
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
Reference in New Issue
Block a user