Support finally blocks in non-local returns

This commit is contained in:
Mikhael Bogdanov
2019-04-04 17:08:16 +02:00
parent 4c59d161d4
commit 30aeb8dc0a
42 changed files with 146 additions and 137 deletions
@@ -109,9 +109,12 @@ class ExpressionCodegen(
val irFunction: IrFunction,
val frame: IrFrameMap,
val mv: InstructionAdapter,
val classCodegen: ClassCodegen
val classCodegen: ClassCodegen,
val isInlineLambda: Boolean = false
) : IrElementVisitor<StackValue, BlockInfo>, BaseExpressionCodegen {
var finallyDepth = 0
/*TODO*/
val intrinsics = IrIntrinsicMethods(classCodegen.context.irBuiltIns)
@@ -331,7 +334,7 @@ class ExpressionCodegen(
}
fun generateCall(expression: IrMemberAccessExpression, callable: Callable, data: BlockInfo, isSuperCall: Boolean = false): StackValue {
val callGenerator = getOrCreateCallGenerator(expression, expression.descriptor)
val callGenerator = getOrCreateCallGenerator(expression, expression.descriptor, data)
val receiver = expression.dispatchReceiver
receiver?.apply {
@@ -1123,7 +1126,17 @@ class ExpressionCodegen(
private fun genFinallyBlock(tryInfo: TryInfo, tryCatchBlockEnd: Label?, afterJumpLabel: Label?, data: BlockInfo) {
assert(tryInfo.gaps.size % 2 == 0) { "Finally block gaps are inconsistent" }
tryInfo.gaps.add(markNewLabel())
finallyDepth++
if (isFinallyMarkerRequired()) {
generateFinallyMarker(mv, finallyDepth, true)
}
gen(tryInfo.tryBlock.finallyExpression!!, data).discard()
if (isFinallyMarkerRequired()) {
generateFinallyMarker(mv, finallyDepth, false)
}
finallyDepth--
if (tryCatchBlockEnd != null) {
tryInfo.tryBlock.finallyExpression!!.markLineNumber(startOffset = false)
mv.goTo(tryCatchBlockEnd)
@@ -1131,7 +1144,7 @@ class ExpressionCodegen(
tryInfo.gaps.add(afterJumpLabel ?: markNewLabel())
}
private fun generateFinallyBlocksIfNeeded(returnType: Type, afterReturnLabel: Label, data: BlockInfo) {
fun generateFinallyBlocksIfNeeded(returnType: Type, afterReturnLabel: Label, data: BlockInfo) {
if (data.hasFinallyBlocks()) {
if (Type.VOID_TYPE != returnType) {
val returnValIndex = frame.enterTemp(returnType)
@@ -1226,7 +1239,8 @@ class ExpressionCodegen(
descriptor: CallableDescriptor,
element: IrMemberAccessExpression?,
typeParameterMappings: TypeParameterMappings?,
isDefaultCompilation: Boolean
isDefaultCompilation: Boolean,
data: BlockInfo
): IrCallGenerator {
if (element == null) return IrCallGenerator.DefaultCallGenerator
@@ -1240,13 +1254,14 @@ class ExpressionCodegen(
return if (isDefaultCompilation) {
TODO()
} else {
IrInlineCodegen(this, state, original, typeParameterMappings!!, IrSourceCompilerForInline(state, element, this))
IrInlineCodegen(this, state, original, typeParameterMappings!!, IrSourceCompilerForInline(state, element, this, data))
}
}
internal fun getOrCreateCallGenerator(
memberAccessExpression: IrMemberAccessExpression,
descriptor: CallableDescriptor
descriptor: CallableDescriptor,
data: BlockInfo
): IrCallGenerator {
val typeArguments =
if (memberAccessExpression.typeArgumentsCount == 0) {
@@ -1280,7 +1295,7 @@ class ExpressionCodegen(
}
}
return getOrCreateCallGenerator(descriptor, memberAccessExpression, mappings, false)
return getOrCreateCallGenerator(descriptor, memberAccessExpression, mappings, false, data)
}
override val frameMap: IrFrameMap
@@ -1311,6 +1326,10 @@ class ExpressionCodegen(
override fun markLineNumberAfterInlineIfNeeded() {
//TODO
}
fun isFinallyMarkerRequired(): Boolean {
return irFunction.isInline || isInlineLambda
}
}
fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isConstructor: Boolean, codegen: ExpressionCodegen): Boolean {
@@ -27,7 +27,11 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
open class FunctionCodegen(private val irFunction: IrFunction, private val classCodegen: ClassCodegen) {
open class FunctionCodegen(
private val irFunction: IrFunction,
private val classCodegen: ClassCodegen,
private val isInlineLambda: Boolean = false
) {
val state = classCodegen.state
@@ -56,7 +60,7 @@ open class FunctionCodegen(private val irFunction: IrFunction, private val class
methodVisitor.visitEnd()
} else {
val frameMap = createFrameMapWithReceivers(classCodegen.state, irFunction, signature)
ExpressionCodegen(irFunction, frameMap, InstructionAdapter(methodVisitor), classCodegen).generate()
ExpressionCodegen(irFunction, frameMap, InstructionAdapter(methodVisitor), classCodegen, isInlineLambda).generate()
}
return signature
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.codegen.BaseExpressionCodegen
import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.inline.*
@@ -37,13 +38,15 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class IrSourceCompilerForInline(
override val state: GenerationState,
override val callElement: IrMemberAccessExpression,
private val codegen: ExpressionCodegen
private val codegen: ExpressionCodegen,
private val data: BlockInfo
) : SourceCompilerForInline {
@@ -71,7 +74,7 @@ class IrSourceCompilerForInline(
override fun generateLambdaBody(adapter: MethodVisitor, jvmMethodSignature: JvmMethodSignature, lambdaInfo: ExpressionLambda): SMAP {
lambdaInfo as? IrExpressionLambdaImpl ?: error("Expecting ir lambda, but $lambdaInfo")
val functionCodegen = object : FunctionCodegen(lambdaInfo.function, codegen.classCodegen) {
val functionCodegen = object : FunctionCodegen(lambdaInfo.function, codegen.classCodegen, true) {
override fun createMethod(flags: Int, signature: JvmMethodGenericSignature): MethodVisitor {
return adapter
}
@@ -135,22 +138,27 @@ class IrSourceCompilerForInline(
return SMAPAndMethodNode(node!!, SMAP(fakeClassCodegen.getOrCreateSourceMapper().resultMappings))
}
override fun generateAndInsertFinallyBlocks(
intoNode: MethodNode,
insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>,
offsetForFinallyLocalVar: Int
) {
//TODO("not implemented")
override fun hasFinallyBlocks() = data.hasFinallyBlocks()
override fun generateFinallyBlocksIfNeeded(finallyCodegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label) {
require(finallyCodegen is ExpressionCodegen)
finallyCodegen.generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data)
}
override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) =
ExpressionCodegen(
codegen.irFunction, codegen.frame, InstructionAdapter(finallyNode), codegen.classCodegen, codegen.isInlineLambda
).also {
it.finallyDepth = curFinallyDepth
}
override fun isCallInsideSameModuleAsDeclared(functionDescriptor: FunctionDescriptor): Boolean {
//TODO("not implemented")
return true
}
override fun isFinallyMarkerRequired(): Boolean {
//TODO("not implemented")
return false
return codegen.isFinallyMarkerRequired()
}
override val compilationContextDescriptor: DeclarationDescriptor