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:
+1
-1
@@ -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) {
|
||||||
|
|||||||
+40
@@ -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,
|
||||||
|
|||||||
+52
-40
@@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-4
@@ -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
|
||||||
|
|||||||
+16
-8
@@ -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]
|
||||||
+24
@@ -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
|
||||||
|
}
|
||||||
+5
@@ -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]
|
||||||
+8
@@ -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]
|
||||||
|
}
|
||||||
+22
@@ -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
|
||||||
|
}
|
||||||
+19
@@ -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
|
||||||
|
}
|
||||||
+25
@@ -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
|
||||||
|
}
|
||||||
+25
@@ -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
|
||||||
|
}
|
||||||
+40
@@ -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");
|
||||||
|
|||||||
Generated
+40
@@ -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");
|
||||||
|
|||||||
Generated
+40
@@ -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");
|
||||||
|
|||||||
+40
@@ -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");
|
||||||
|
|||||||
Generated
+40
@@ -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");
|
||||||
|
|||||||
Generated
+40
@@ -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");
|
||||||
|
|||||||
+40
@@ -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");
|
||||||
|
|||||||
Generated
+40
@@ -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");
|
||||||
|
|||||||
Generated
+40
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user