JVM_IR: support non-local break/continue in the inliner

Not in the frontend or psi2ir, though, so this not a complete
implementation of KT-1436, but rather a part of it that is currently
useful to make other code compile. In particular, lambdas passed to
array constructors and JVM-style `assert` are inlined as IR returnable
blocks, which are then converted into `do { ... } while (false)` loops,
so non-local returns from them become non-local `break`s.
This commit is contained in:
pyos
2020-02-18 12:48:59 +01:00
committed by max-kammerer
parent 4a17228621
commit 0f2ca5d84c
28 changed files with 660 additions and 155 deletions
@@ -319,7 +319,7 @@ class AnonymousObjectTransformer(
), null ), null
) )
val result = inliner.doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, ReturnLabelOwner.NOT_APPLICABLE) val result = inliner.doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, mapOf())
result.reifiedTypeParametersUsages.mergeAll(typeParametersToReify) result.reifiedTypeParametersUsages.mergeAll(typeParametersToReify)
deferringVisitor.visitMaxs(-1, -1) deferringVisitor.visitMaxs(-1, -1)
return result return result
@@ -243,12 +243,10 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
//hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain //hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
adapter.visitInsn(Opcodes.NOP) adapter.visitInsn(Opcodes.NOP)
val result = inliner.doInline(adapter, remapper, true, ReturnLabelOwner.SKIP_ALL) val result = inliner.doInline(adapter, remapper, true, mapOf())
result.reifiedTypeParametersUsages.mergeAll(reificationResult) result.reifiedTypeParametersUsages.mergeAll(reificationResult)
val labels = sourceCompiler.getContextLabels() val infos = MethodInliner.processReturns(adapter, sourceCompiler.getContextLabels(), null)
val infos = MethodInliner.processReturns(adapter, ReturnLabelOwner { labels.contains(it) }, true, null)
generateAndInsertFinallyBlocks( generateAndInsertFinallyBlocks(
adapter, infos, (remapper.remap(parameters.argsSizeOnStack + 1).value as StackValue.Local).index adapter, infos, (remapper.remap(parameters.argsSizeOnStack + 1).value as StackValue.Local).index
) )
@@ -319,7 +317,9 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
frameMap.enterTemp(Type.INT_TYPE) frameMap.enterTemp(Type.INT_TYPE)
} }
sourceCompiler.generateFinallyBlocksIfNeeded(finallyCodegen, extension.returnType, extension.finallyIntervalEnd.label) sourceCompiler.generateFinallyBlocksIfNeeded(
finallyCodegen, extension.returnType, extension.finallyIntervalEnd.label, extension.jumpTarget
)
//Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
insertNodeBefore(finallyNode, intoNode, curInstr) insertNodeBefore(finallyNode, intoNode, curInstr)
@@ -30,17 +30,14 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.org.objectweb.asm.ClassReader import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.ClassVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
import kotlin.properties.Delegates import kotlin.properties.Delegates
interface FunctionalArgument interface FunctionalArgument
abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgument, ReturnLabelOwner { abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgument {
abstract val isBoundCallableReference: Boolean abstract val isBoundCallableReference: Boolean
@@ -54,6 +51,9 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu
abstract val capturedVars: List<CapturedParamDesc> abstract val capturedVars: List<CapturedParamDesc>
open val returnLabels: Map<String, Label?>
get() = mapOf()
lateinit var node: SMAPAndMethodNode lateinit var node: SMAPAndMethodNode
abstract fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>) abstract fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>)
@@ -129,8 +129,6 @@ abstract class DefaultLambda(
final override lateinit var capturedVars: List<CapturedParamDesc> final override lateinit var capturedVars: List<CapturedParamDesc>
private set private set
override fun isReturnFromMe(labelName: String): Boolean = false
var originalBoundReceiverType: Type? = null var originalBoundReceiverType: Type? = null
private set private set
@@ -247,7 +245,7 @@ class PsiExpressionLambda(
val functionWithBodyOrCallableReference: KtExpression = (expression as? KtLambdaExpression)?.functionLiteral ?: expression val functionWithBodyOrCallableReference: KtExpression = (expression as? KtLambdaExpression)?.functionLiteral ?: expression
private val labels: Set<String> override val returnLabels: Map<String, Label?>
override val isSuspend: Boolean override val isSuspend: Boolean
@@ -284,7 +282,7 @@ class PsiExpressionLambda(
closure = it!! closure = it!!
} }
labels = InlineCodegen.getDeclarationLabels(expression, invokeMethodDescriptor) returnLabels = InlineCodegen.getDeclarationLabels(expression, invokeMethodDescriptor).associateWith { null }
invokeMethod = typeMapper.mapAsmMethod(invokeMethodDescriptor) invokeMethod = typeMapper.mapAsmMethod(invokeMethodDescriptor)
isSuspend = invokeMethodDescriptor.isSuspend isSuspend = invokeMethodDescriptor.isSuspend
} }
@@ -324,10 +322,6 @@ class PsiExpressionLambda(
} }
} }
override fun isReturnFromMe(labelName: String): Boolean {
return labels.contains(labelName)
}
val isPropertyReference: Boolean val isPropertyReference: Boolean
get() = propertyReferenceInfo != null get() = propertyReferenceInfo != null
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ParameterDescriptor
@@ -72,9 +73,9 @@ class MethodInliner(
adapter: MethodVisitor, adapter: MethodVisitor,
remapper: LocalVarRemapper, remapper: LocalVarRemapper,
remapReturn: Boolean, remapReturn: Boolean,
returnLabelOwner: ReturnLabelOwner returnLabels: Map<String, Label?>
): InlineResult { ): InlineResult {
return doInline(adapter, remapper, remapReturn, returnLabelOwner, 0) return doInline(adapter, remapper, remapReturn, returnLabels, 0)
} }
private fun recordTransformation(info: TransformationInfo) { private fun recordTransformation(info: TransformationInfo) {
@@ -91,11 +92,11 @@ class MethodInliner(
adapter: MethodVisitor, adapter: MethodVisitor,
remapper: LocalVarRemapper, remapper: LocalVarRemapper,
remapReturn: Boolean, remapReturn: Boolean,
returnLabelOwner: ReturnLabelOwner, returnLabels: Map<String, Label?>,
finallyDeepShift: Int finallyDeepShift: Int
): InlineResult { ): InlineResult {
//analyze body //analyze body
var transformedNode = markPlacesForInlineAndRemoveInlinable(node, returnLabelOwner, finallyDeepShift) var transformedNode = markPlacesForInlineAndRemoveInlinable(node, returnLabels, finallyDeepShift)
if (inliningContext.isInliningLambda && isDefaultLambdaWithReification(inliningContext.lambdaInfo!!)) { if (inliningContext.isInliningLambda && isDefaultLambdaWithReification(inliningContext.lambdaInfo!!)) {
//TODO maybe move reification in one place //TODO maybe move reification in one place
inliningContext.root.inlineMethodReifier.reifyInstructions(transformedNode) inliningContext.root.inlineMethodReifier.reifyInstructions(transformedNode)
@@ -139,7 +140,9 @@ class MethodInliner(
) )
} }
processReturns(resultNode, returnLabelOwner, remapReturn, end) if (remapReturn) {
processReturns(resultNode, returnLabels, end)
}
//flush transformed node to output //flush transformed node to output
resultNode.accept(SkipMaxAndEndVisitor(adapter)) resultNode.accept(SkipMaxAndEndVisitor(adapter))
return result return result
@@ -297,7 +300,7 @@ class MethodInliner(
val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift) val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift)
//TODO add skipped this and receiver //TODO add skipped this and receiver
val lambdaResult = inliner.doInline(localVariablesSorter, varRemapper, true, info, invokeCall.finallyDepthShift) val lambdaResult = inliner.doInline(localVariablesSorter, varRemapper, true, info.returnLabels, invokeCall.finallyDepthShift)
result.mergeWithNotChangeInfo(lambdaResult) result.mergeWithNotChangeInfo(lambdaResult)
result.reifiedTypeParametersUsages.mergeAll(lambdaResult.reifiedTypeParametersUsages) result.reifiedTypeParametersUsages.mergeAll(lambdaResult.reifiedTypeParametersUsages)
@@ -486,11 +489,11 @@ class MethodInliner(
} }
private fun markPlacesForInlineAndRemoveInlinable( private fun markPlacesForInlineAndRemoveInlinable(
node: MethodNode, returnLabelOwner: ReturnLabelOwner, finallyDeepShift: Int node: MethodNode, returnLabels: Map<String, Label?>, finallyDeepShift: Int
): MethodNode { ): MethodNode {
val processingNode = prepareNode(node, finallyDeepShift) val processingNode = prepareNode(node, finallyDeepShift)
preprocessNodeBeforeInline(processingNode, returnLabelOwner) preprocessNodeBeforeInline(processingNode, returnLabels)
replaceContinuationAccessesWithFakeContinuationsIfNeeded(processingNode) replaceContinuationAccessesWithFakeContinuationsIfNeeded(processingNode)
@@ -765,7 +768,7 @@ class MethodInliner(
} }
} }
private fun preprocessNodeBeforeInline(node: MethodNode, returnLabelOwner: ReturnLabelOwner) { private fun preprocessNodeBeforeInline(node: MethodNode, returnLabels: Map<String, Label?>) {
try { try {
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node) FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
} catch (e: Throwable) { } catch (e: Throwable) {
@@ -787,16 +790,13 @@ class MethodInliner(
if (!isReturnOpcode(insnNode.opcode)) continue if (!isReturnOpcode(insnNode.opcode)) continue
var insertBeforeInsn = insnNode
// TODO extract isLocalReturn / isNonLocalReturn, see processReturns // TODO extract isLocalReturn / isNonLocalReturn, see processReturns
val labelName = getMarkedReturnLabelOrNull(insnNode) val labelName = getMarkedReturnLabelOrNull(insnNode)
if (labelName != null) { if (labelName == null) {
if (!returnLabelOwner.isReturnFromMe(labelName)) continue localReturnsNormalizer.addLocalReturnToTransform(insnNode, insnNode, frame)
insertBeforeInsn = insnNode.previous } else if (labelName in returnLabels) {
localReturnsNormalizer.addLocalReturnToTransform(insnNode, insnNode.previous, frame)
} }
localReturnsNormalizer.addLocalReturnToTransform(insnNode, insertBeforeInsn, frame)
} }
localReturnsNormalizer.transform(node) localReturnsNormalizer.transform(node)
@@ -1001,7 +1001,8 @@ class MethodInliner(
class PointForExternalFinallyBlocks( class PointForExternalFinallyBlocks(
@JvmField val beforeIns: AbstractInsnNode, @JvmField val beforeIns: AbstractInsnNode,
@JvmField val returnType: Type, @JvmField val returnType: Type,
@JvmField val finallyIntervalEnd: LabelNode @JvmField val finallyIntervalEnd: LabelNode,
@JvmField val jumpTarget: Label?
) )
companion object { companion object {
@@ -1115,55 +1116,44 @@ class MethodInliner(
//process local and global returns (local substituted with goto end-label global kept unchanged) //process local and global returns (local substituted with goto end-label global kept unchanged)
@JvmStatic @JvmStatic
fun processReturns( fun processReturns(
node: MethodNode, returnLabelOwner: ReturnLabelOwner, remapReturn: Boolean, endLabel: Label? node: MethodNode, returnLabels: Map<String, Label?>, endLabel: Label?
): List<PointForExternalFinallyBlocks> { ): List<PointForExternalFinallyBlocks> {
if (!remapReturn) {
return emptyList()
}
val result = ArrayList<PointForExternalFinallyBlocks>() val result = ArrayList<PointForExternalFinallyBlocks>()
val instructions = node.instructions val instructions = node.instructions
var insnNode: AbstractInsnNode? = instructions.first var insnNode: AbstractInsnNode? = instructions.first
while (insnNode != null) { while (insnNode != null) {
if (isReturnOpcode(insnNode.opcode)) { if (isReturnOpcode(insnNode.opcode)) {
var isLocalReturn = true
val labelName = getMarkedReturnLabelOrNull(insnNode) val labelName = getMarkedReturnLabelOrNull(insnNode)
val returnType = getReturnType(insnNode.opcode)
if (labelName != null) { val isLocalReturn = labelName == null || labelName in returnLabels
isLocalReturn = returnLabelOwner.isReturnFromMe(labelName) val jumpTarget = returnLabels[labelName] ?: endLabel
//remove global return flag
if (isLocalReturn) { if (isLocalReturn && labelName != null) {
instructions.remove(insnNode.previous) // remove non-local return flag
} instructions.remove(insnNode.previous)
} }
if (isLocalReturn && endLabel != null) { if (isLocalReturn && jumpTarget != null) {
val nop = InsnNode(Opcodes.NOP) val jumpInsnNode = JumpInsnNode(Opcodes.GOTO, jumpTarget.info as LabelNode)
instructions.insert(insnNode, nop) instructions.insertBefore(insnNode, InsnNode(Opcodes.NOP))
if (jumpTarget != endLabel) {
val labelNode = endLabel.info as LabelNode instructions.insertBefore(insnNode, PseudoInsn.FIX_STACK_BEFORE_JUMP.createInsnNode())
val jumpInsnNode = JumpInsnNode(Opcodes.GOTO, labelNode) }
instructions.insert(nop, jumpInsnNode) instructions.insertBefore(insnNode, jumpInsnNode)
instructions.remove(insnNode) instructions.remove(insnNode)
insnNode = jumpInsnNode insnNode = jumpInsnNode
} }
//generate finally block before nonLocalReturn flag/return/goto
val label = LabelNode() val label = LabelNode()
instructions.insert(insnNode, label) instructions.insert(insnNode, label)
result.add( // generate finally blocks before the non-local return flag or the stack fixup pseudo instruction
PointForExternalFinallyBlocks( val finallyInsertionPoint = if (isLocalReturn && jumpTarget == endLabel) insnNode else insnNode.previous
getInstructionToInsertFinallyBefore(insnNode, isLocalReturn), getReturnType(insnNode.opcode), label result.add(PointForExternalFinallyBlocks(finallyInsertionPoint, returnType, label, jumpTarget))
)
)
} }
insnNode = insnNode.next insnNode = insnNode.next
} }
return result return result
} }
private fun getInstructionToInsertFinallyBefore(nonLocalReturnOrJump: AbstractInsnNode, isLocal: Boolean): AbstractInsnNode {
return if (isLocal) nonLocalReturnOrJump else nonLocalReturnOrJump.previous
}
} }
} }
@@ -1,29 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.inline;
import org.jetbrains.annotations.NotNull;
public interface ReturnLabelOwner {
boolean isReturnFromMe(@NotNull String labelName);
ReturnLabelOwner SKIP_ALL = name -> false;
ReturnLabelOwner NOT_APPLICABLE = name -> {
throw new RuntimeException("This operation not applicable for current context");
};
}
@@ -64,7 +64,7 @@ interface SourceCompilerForInline {
curFinallyDepth: Int curFinallyDepth: Int
): BaseExpressionCodegen ): BaseExpressionCodegen
fun generateFinallyBlocksIfNeeded(finallyCodegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label) fun generateFinallyBlocksIfNeeded(codegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label, target: Label?)
fun isCallInsideSameModuleAsDeclared(functionDescriptor: FunctionDescriptor): Boolean fun isCallInsideSameModuleAsDeclared(functionDescriptor: FunctionDescriptor): Boolean
@@ -74,7 +74,7 @@ interface SourceCompilerForInline {
val compilationContextFunctionDescriptor: FunctionDescriptor val compilationContextFunctionDescriptor: FunctionDescriptor
fun getContextLabels(): Set<String> fun getContextLabels(): Map<String, Label?>
fun reportSuspensionPointInsideMonitor(stackTraceElement: String) fun reportSuspensionPointInsideMonitor(stackTraceElement: String)
} }
@@ -311,9 +311,10 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
override fun hasFinallyBlocks() = codegen.hasFinallyBlocks() override fun hasFinallyBlocks() = codegen.hasFinallyBlocks()
override fun generateFinallyBlocksIfNeeded(finallyCodegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label) { override fun generateFinallyBlocksIfNeeded(codegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label, target: Label?) {
require(finallyCodegen is ExpressionCodegen) // TODO use the target label for non-local break/continue
finallyCodegen.generateFinallyBlocksIfNeeded(returnType, null, afterReturnLabel) require(codegen is ExpressionCodegen)
codegen.generateFinallyBlocksIfNeeded(returnType, null, afterReturnLabel)
} }
override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) = override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) =
@@ -337,14 +338,15 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
override val compilationContextFunctionDescriptor override val compilationContextFunctionDescriptor
get() = codegen.getContext().functionDescriptor get() = codegen.getContext().functionDescriptor
override fun getContextLabels(): Set<String> { override fun getContextLabels(): Map<String, Label?> {
val context = codegen.getContext() val context = codegen.getContext()
val parentContext = context.parentContext val parentContext = context.parentContext
val descriptor = if (parentContext is ClosureContext && parentContext.originalSuspendLambdaDescriptor != null) { val descriptor = if (parentContext is ClosureContext && parentContext.originalSuspendLambdaDescriptor != null) {
parentContext.originalSuspendLambdaDescriptor!! parentContext.originalSuspendLambdaDescriptor!!
} else context.contextDescriptor } else context.contextDescriptor
return InlineCodegen.getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor) val labels = InlineCodegen.getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor)
return labels.associateWith { null } // TODO add break/continue labels
} }
fun initializeInlineFunctionContext(functionDescriptor: FunctionDescriptor) { fun initializeInlineFunctionContext(functionDescriptor: FunctionDescriptor) {
@@ -2420,6 +2420,46 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");
@@ -313,8 +313,6 @@ private val jvmFilePhases = listOf(
collectionStubMethodLowering, collectionStubMethodLowering,
jvmInlineClassPhase, jvmInlineClassPhase,
sharedVariablesPhase,
makePatchParentsPhase(1), makePatchParentsPhase(1),
enumWhenPhase, enumWhenPhase,
@@ -323,6 +321,7 @@ private val jvmFilePhases = listOf(
singleAbstractMethodPhase, singleAbstractMethodPhase,
assertionPhase, assertionPhase,
returnableBlocksPhase, returnableBlocksPhase,
sharedVariablesPhase,
localDeclarationsPhase, localDeclarationsPhase,
jvmLocalClassExtractionPhase, jvmLocalClassExtractionPhase,
staticCallableReferencePhase, staticCallableReferencePhase,
@@ -80,7 +80,7 @@ class TryWithFinallyInfo(val onExit: IrExpression) : TryInfo()
class BlockInfo(val parent: BlockInfo? = null) { class BlockInfo(val parent: BlockInfo? = null) {
val variables = mutableListOf<VariableInfo>() val variables = mutableListOf<VariableInfo>()
private val infos: Stack<ExpressionInfo> = parent?.infos ?: Stack() val infos: Stack<ExpressionInfo> = parent?.infos ?: Stack()
fun hasFinallyBlocks(): Boolean = infos.firstIsInstanceOrNull<TryWithFinallyInfo>() != null fun hasFinallyBlocks(): Boolean = infos.firstIsInstanceOrNull<TryWithFinallyInfo>() != null
@@ -869,42 +869,39 @@ class ExpressionCodegen(
return unitValue return unitValue
} }
private fun generateGlobalReturnFlagIfPossible(expression: IrExpression, label: String) {
if (state.isInlineDisabled) {
context.psiErrorBuilder.at(expression, irFunction).report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE)
genThrow(mv, "java/lang/UnsupportedOperationException", "Non-local returns are not allowed with inlining disabled")
} else {
generateGlobalReturnFlag(mv, label)
}
}
override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue { override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue {
val returnTarget = expression.returnTargetSymbol.owner val returnTarget = expression.returnTargetSymbol.owner
val owner = val owner = returnTarget as? IrFunction ?: error("Unsupported IrReturnTarget: $returnTarget")
returnTarget as? IrFunction // TODO: should be owner != irFunction
?: (returnTarget as? IrReturnableBlock)?.inlineFunctionSymbol?.owner val isNonLocalReturn = methodSignatureMapper.mapFunctionName(owner) != methodSignatureMapper.mapFunctionName(irFunction)
?: error("Unsupported IrReturnTarget: $returnTarget")
//TODO: should be owner != irFunction
val isNonLocalReturn =
methodSignatureMapper.mapFunctionName(owner) != methodSignatureMapper.mapFunctionName(irFunction)
if (isNonLocalReturn && state.isInlineDisabled) {
context.psiErrorBuilder.at(expression, owner).report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE)
genThrow(
mv, "java/lang/UnsupportedOperationException",
"Non-local returns are not allowed with inlining disabled"
)
return unitValue
}
var returnType = if (owner == irFunction) signature.returnType else methodSignatureMapper.mapReturnType(owner) var returnType = if (owner == irFunction) signature.returnType else methodSignatureMapper.mapReturnType(owner)
var returnIrType = owner.returnType var returnIrType = owner.returnType
val unboxedInlineClass = owner.suspendFunctionOriginal().originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass() val unboxedInlineClass = owner.suspendFunctionOriginal().originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass()
if (unboxedInlineClass != null) { if (unboxedInlineClass != null) {
returnIrType = unboxedInlineClass returnIrType = unboxedInlineClass
returnType = unboxedInlineClass.asmType returnType = unboxedInlineClass.asmType
} }
val afterReturnLabel = Label() val afterReturnLabel = Label()
expression.value.accept(this, data).materializeAt(returnType, returnIrType) expression.value.accept(this, data).materializeAt(returnType, returnIrType)
// In case of non-local return from suspend lambda 'materializeAt' does not box return value, box it manually. // In case of non-local return from suspend lambda 'materializeAt' does not box return value, box it manually.
if (isNonLocalReturn && owner.isInvokeSuspendOfLambda() && expression.value.type.isKotlinResult()) { if (isNonLocalReturn && owner.isInvokeSuspendOfLambda() && expression.value.type.isKotlinResult()) {
StackValue.boxInlineClass(expression.value.type.toIrBasedKotlinType(), mv) StackValue.boxInlineClass(expression.value.type.toIrBasedKotlinType(), mv)
} }
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data) generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data, null)
expression.markLineNumber(startOffset = true) expression.markLineNumber(startOffset = true)
if (isNonLocalReturn) { if (isNonLocalReturn) {
generateGlobalReturnFlag(mv, owner.name.asString()) generateGlobalReturnFlagIfPossible(expression, owner.name.asString())
} }
mv.areturn(returnType) mv.areturn(returnType)
mv.mark(afterReturnLabel) mv.mark(afterReturnLabel)
@@ -1012,9 +1009,15 @@ class ExpressionCodegen(
} }
override fun visitWhileLoop(loop: IrWhileLoop, data: BlockInfo): PromisedValue { override fun visitWhileLoop(loop: IrWhileLoop, data: BlockInfo): PromisedValue {
val continueLabel = markNewLabel() // Spill the stack in case the loop contains inline functions that break/continue
val endLabel = Label() // out of it. (The case where a loop is entered with a non-empty stack is rare, but
// Mark stack depth for break // possible; basically, you need to either use `Array(n) { ... }` or put a `when`
// containing a loop as an argument to a function call.)
addInlineMarker(mv, true)
val continueLabel = markNewLinkedLabel()
val endLabel = linkedLabel()
// Mark the label as having 0 stack depth, so that `break`/`continue` inside
// expressions pop all elements off it before jumping.
mv.fakeAlwaysFalseIfeq(endLabel) mv.fakeAlwaysFalseIfeq(endLabel)
loop.condition.markLineNumber(true) loop.condition.markLineNumber(true)
loop.condition.accept(this, data).coerceToBoolean().jumpIfFalse(endLabel) loop.condition.accept(this, data).coerceToBoolean().jumpIfFalse(endLabel)
@@ -1023,14 +1026,16 @@ class ExpressionCodegen(
} }
mv.goTo(continueLabel) mv.goTo(continueLabel)
mv.mark(endLabel) mv.mark(endLabel)
addInlineMarker(mv, false)
return unitValue return unitValue
} }
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: BlockInfo): PromisedValue { override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: BlockInfo): PromisedValue {
// See comments in `visitWhileLoop`
addInlineMarker(mv, true)
val entry = markNewLabel() val entry = markNewLabel()
val endLabel = Label() val endLabel = linkedLabel()
val continueLabel = Label() val continueLabel = linkedLabel()
// Mark stack depth for break/continue
mv.fakeAlwaysFalseIfeq(continueLabel) mv.fakeAlwaysFalseIfeq(continueLabel)
mv.fakeAlwaysFalseIfeq(endLabel) mv.fakeAlwaysFalseIfeq(endLabel)
data.withBlock(LoopInfo(loop, continueLabel, endLabel)) { data.withBlock(LoopInfo(loop, continueLabel, endLabel)) {
@@ -1040,6 +1045,7 @@ class ExpressionCodegen(
loop.condition.markLineNumber(true) loop.condition.markLineNumber(true)
loop.condition.accept(this, data).coerceToBoolean().jumpIfTrue(entry) loop.condition.accept(this, data).coerceToBoolean().jumpIfTrue(entry)
mv.mark(endLabel) mv.mark(endLabel)
addInlineMarker(mv, false)
return unitValue return unitValue
} }
@@ -1047,26 +1053,32 @@ class ExpressionCodegen(
endLabel: Label, endLabel: Label,
data: BlockInfo, data: BlockInfo,
nestedTryWithoutFinally: MutableList<TryInfo> = arrayListOf(), nestedTryWithoutFinally: MutableList<TryInfo> = arrayListOf(),
stop: (ExpressionInfo) -> Boolean = { false } stop: (LoopInfo) -> Boolean
): ExpressionInfo? { ): LoopInfo? {
return data.handleBlock { return data.handleBlock {
if (it is TryWithFinallyInfo) { when {
genFinallyBlock(it, null, endLabel, data, nestedTryWithoutFinally) it is TryWithFinallyInfo -> {
nestedTryWithoutFinally.clear() genFinallyBlock(it, null, endLabel, data, nestedTryWithoutFinally)
} else if (it is TryInfo) { nestedTryWithoutFinally.clear()
nestedTryWithoutFinally.add(it) }
it is TryInfo -> nestedTryWithoutFinally.add(it)
it is LoopInfo && stop(it) -> return it
} }
return if (stop(it)) it else unwindBlockStack(endLabel, data, nestedTryWithoutFinally, stop) return unwindBlockStack(endLabel, data, nestedTryWithoutFinally, stop)
} }
} }
override fun visitBreakContinue(jump: IrBreakContinue, data: BlockInfo): PromisedValue { override fun visitBreakContinue(jump: IrBreakContinue, data: BlockInfo): PromisedValue {
jump.markLineNumber(startOffset = true) jump.markLineNumber(startOffset = true)
val endLabel = Label() val endLabel = Label()
val stackElement = unwindBlockStack(endLabel, data) { it is LoopInfo && it.loop == jump.loop } as LoopInfo? val stackElement = unwindBlockStack(endLabel, data) { it.loop == jump.loop }
?: throw AssertionError("Target label for break/continue not found") if (stackElement == null) {
mv.fixStackAndJump(if (jump is IrBreak) stackElement.breakLabel else stackElement.continueLabel) generateGlobalReturnFlagIfPossible(jump, jump.loop.nonLocalReturnLabel(jump is IrBreak))
mv.mark(endLabel) mv.areturn(Type.VOID_TYPE)
} else {
mv.fixStackAndJump(if (jump is IrBreak) stackElement.breakLabel else stackElement.continueLabel)
mv.mark(endLabel)
}
return unitValue return unitValue
} }
@@ -1214,16 +1226,16 @@ class ExpressionCodegen(
} }
} }
fun generateFinallyBlocksIfNeeded(returnType: Type, afterReturnLabel: Label, data: BlockInfo) { fun generateFinallyBlocksIfNeeded(returnType: Type, afterReturnLabel: Label, data: BlockInfo, jumpLabel: Label?) {
if (data.hasFinallyBlocks()) { if (data.hasFinallyBlocks()) {
if (Type.VOID_TYPE != returnType) { if (Type.VOID_TYPE != returnType) {
val returnValIndex = frameMap.enterTemp(returnType) val returnValIndex = frameMap.enterTemp(returnType)
mv.store(returnValIndex, returnType) mv.store(returnValIndex, returnType)
unwindBlockStack(afterReturnLabel, data) unwindBlockStack(afterReturnLabel, data) { it.breakLabel == jumpLabel || it.continueLabel == jumpLabel }
mv.load(returnValIndex, returnType) mv.load(returnValIndex, returnType)
frameMap.leaveTemp(returnType) frameMap.leaveTemp(returnType)
} else { } else {
unwindBlockStack(afterReturnLabel, data) unwindBlockStack(afterReturnLabel, data) { it.breakLabel == jumpLabel || it.continueLabel == jumpLabel }
} }
} }
} }
@@ -181,10 +181,6 @@ class IrExpressionLambdaImpl(
override val isSuspend: Boolean = function.isSuspend override val isSuspend: Boolean = function.isSuspend
override fun isReturnFromMe(labelName: String): Boolean {
return false //always false
}
// This name doesn't actually matter: it is used internally to tell this lambda's captured // This name doesn't actually matter: it is used internally to tell this lambda's captured
// arguments apart from any other scope's. So long as it's unique, any value is fine. // arguments apart from any other scope's. So long as it's unique, any value is fine.
// This particular string slightly aids in debugging internal compiler errors as it at least // This particular string slightly aids in debugging internal compiler errors as it at least
@@ -24,10 +24,10 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBasedSimpleFunctionDescriptor import org.jetbrains.kotlin.ir.descriptors.IrBasedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.util.isSuspend import org.jetbrains.kotlin.ir.util.isSuspend
import org.jetbrains.kotlin.ir.util.module import org.jetbrains.kotlin.ir.util.module
import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.doNotAnalyze import org.jetbrains.kotlin.psi.doNotAnalyze
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR
@@ -36,7 +36,6 @@ import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.io.File
class IrSourceCompilerForInline( class IrSourceCompilerForInline(
override val state: GenerationState, override val state: GenerationState,
@@ -107,9 +106,9 @@ class IrSourceCompilerForInline(
override fun hasFinallyBlocks() = data.hasFinallyBlocks() override fun hasFinallyBlocks() = data.hasFinallyBlocks()
override fun generateFinallyBlocksIfNeeded(finallyCodegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label) { override fun generateFinallyBlocksIfNeeded(codegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label, target: Label?) {
require(finallyCodegen is ExpressionCodegen) require(codegen is ExpressionCodegen)
finallyCodegen.generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data) codegen.generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data, target)
} }
override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) = override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) =
@@ -139,9 +138,15 @@ class IrSourceCompilerForInline(
override val compilationContextFunctionDescriptor: FunctionDescriptor override val compilationContextFunctionDescriptor: FunctionDescriptor
get() = generateSequence(codegen) { it.inlinedInto }.last().irFunction.toIrBasedDescriptor() get() = generateSequence(codegen) { it.inlinedInto }.last().irFunction.toIrBasedDescriptor()
override fun getContextLabels(): Set<String> { override fun getContextLabels(): Map<String, Label?> {
val name = codegen.irFunction.name.asString() val result = mutableMapOf<String, Label?>(codegen.irFunction.name.asString() to null)
return setOf(name) for (info in data.infos) {
if (info !is LoopInfo)
continue
result[info.loop.nonLocalReturnLabel(false)] = info.continueLabel
result[info.loop.nonLocalReturnLabel(true)] = info.breakLabel
}
return result
} }
// TODO: Find a way to avoid using PSI here // TODO: Find a way to avoid using PSI here
@@ -161,3 +166,6 @@ private tailrec fun IrDeclaration.isInlineOrInsideInline(): Boolean {
if (parent !is IrDeclaration) return false if (parent !is IrDeclaration) return false
return parent.isInlineOrInsideInline() return parent.isInlineOrInsideInline()
} }
// TODO generate better labels; this is unique (includes the object's address), but not very descriptive
internal fun IrLoop.nonLocalReturnLabel(forBreak: Boolean): String = "$this\$${if (forBreak) "break" else "continue"}"
@@ -0,0 +1,5 @@
// FILE: 1.kt
inline fun runReturning(f: () -> Nothing): Nothing = f()
// FILE: 2.kt
fun box() = Array<String>(1) { runReturning { return@Array "OK" } }[0]
@@ -0,0 +1,24 @@
// FILE: 1.kt
inline fun runReturning(f: () -> Nothing): Nothing = f()
// FILE: 2.kt
fun box(): String {
var r = ""
val x = Array<String>(1) ext@{
try {
Array<String>(1) {
try {
runReturning { throw RuntimeException() }
} catch (e: Throwable) {
r += "1"
return@ext "OK"
} finally {
r += "2"
}
}[0]
} finally {
r += "3"
}
}[0]
return if (r == "123") x else r
}
@@ -0,0 +1,5 @@
// FILE: 1.kt
inline fun runReturning(f: () -> Nothing): Nothing = f()
// FILE: 2.kt
fun box() = Array<String>(1) { run { runReturning { return@Array "OK" } } }[0]
@@ -0,0 +1,8 @@
// FILE: 1.kt
inline fun runReturning(f: () -> Nothing): Nothing = f()
// FILE: 2.kt
fun box(): String {
val result = "OK"
return Array<String>(1) { run { runReturning { return@Array result } } }[0]
}
@@ -0,0 +1,22 @@
// FILE: 1.kt
inline fun runReturning(f: () -> Nothing): Nothing = f()
// FILE: 2.kt
fun box(): String {
var r = ""
val x = try {
Array<String>(1) {
try {
runReturning { throw RuntimeException() }
} finally {
r += "1"
}
}[0]
} catch (e: Throwable) {
r += "2"
"OK"
} finally {
r += "3"
}
return if (r == "123") x else r
}
@@ -0,0 +1,19 @@
// FILE: 1.kt
inline fun runReturning(f: () -> Nothing): Nothing = f()
// FILE: 2.kt
fun box(): String {
var r = ""
val x = try {
Array<String>(1) {
try {
runReturning { return@Array "OK" }
} finally {
r += "O"
}
}[0]
} finally {
r += "K"
}
return r
}
@@ -0,0 +1,25 @@
// FILE: 1.kt
inline fun runReturning(f: () -> Nothing): Nothing = f()
// FILE: 2.kt
fun box(): String {
var r = ""
val x = try {
Array<String>(1) ext@{
try {
Array<String>(1) {
try {
runReturning { return@ext "OK" }
} finally {
r += "1"
}
}[0]
} finally {
r += "2"
}
}[0]
} finally {
r += "3"
}
return if (r == "123") x else r
}
@@ -0,0 +1,25 @@
// FILE: 1.kt
inline fun runReturning(f: () -> Nothing): Nothing = f()
// FILE: 2.kt
fun box(): String {
var r = ""
val x = try {
Array<String>(1) ext@{
try {
Array<String>(1) {
try {
runReturning { return@Array "OK" }
} finally {
r += "1"
}
}[0]
} finally {
r += "2"
}
}[0]
} finally {
r += "3"
}
return if (r == "123") x else r
}
@@ -2420,6 +2420,46 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");
@@ -2420,6 +2420,46 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");
@@ -2420,6 +2420,46 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");
@@ -2420,6 +2420,46 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");
@@ -2420,6 +2420,46 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");
@@ -2420,6 +2420,46 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");
@@ -2170,6 +2170,46 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");
@@ -2170,6 +2170,46 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");
@@ -2170,6 +2170,46 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt");
} }
@TestMetadata("fromArrayGenerator.kt")
public void testFromArrayGenerator() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt");
}
@TestMetadata("fromArrayGeneratorCatch.kt")
public void testFromArrayGeneratorCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt");
}
@TestMetadata("fromArrayGeneratorNested.kt")
public void testFromArrayGeneratorNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt");
}
@TestMetadata("fromArrayGeneratorWithCapture.kt")
public void testFromArrayGeneratorWithCapture() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt");
}
@TestMetadata("fromArrayGeneratorWithCatch.kt")
public void testFromArrayGeneratorWithCatch() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt");
}
@TestMetadata("fromArrayGeneratorWithFinally.kt")
public void testFromArrayGeneratorWithFinally() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2.kt")
public void testFromArrayGeneratorWithFinallyX2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt");
}
@TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt")
public void testFromArrayGeneratorWithFinallyX2_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt");
}
@TestMetadata("fromInterfaceDefaultGetter.kt") @TestMetadata("fromInterfaceDefaultGetter.kt")
public void testFromInterfaceDefaultGetter() throws Exception { public void testFromInterfaceDefaultGetter() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt");