Generate suspend markers for inline and crossinline parameters

if they are not inlined, but directly called.
Previously, all inline and crossinline lambda calls were treated by
codegen as if they are always going to be inlined. However, this is not
always the case.

Note, that we cannot generate these markers during codegen, since we
can inline code with no suspension points, but the whole inlined code
will become one giant suspension point. This, of course, breaks
tail-call optimization and, hence, slows down cold streams.

Because of that, we generate these markers, when we are sure, that they
are not going to be inlined. The only place, in which we know that, is
the inliner. During inlining of the inline function, we check, whether
the parameter is inline or crossinline and whether it is not an inline
lambda. If these checks pass, we generate the markers. Noinline
parameters are already covered by the codegen.
 #KT-30706 Fixed
 #KT-26925 Fixed
 #KT-26418 Fixed
This commit is contained in:
Ilmir Usmanov
2019-04-02 21:17:34 +03:00
parent eb1bfac83f
commit 2dee506022
12 changed files with 368 additions and 55 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@@ -19,7 +19,8 @@ enum class ValueKind {
METHOD_HANDLE_IN_DEFAULT,
CAPTURED,
DEFAULT_LAMBDA_CAPTURED_PARAMETER,
NON_INLINEABLE_CALLED_IN_SUSPEND
NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND,
NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER
}
interface CallGenerator {
@@ -134,7 +134,8 @@ class AnonymousObjectTransformer(
inliningContext,
classBuilder,
methodsToTransform,
superClassName
superClassName,
additionalFakeParams
)
for (next in methodsToTransform) {
val deferringVisitor =
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.codegen.inline
import com.intellij.psi.PsiElement
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive
@@ -409,8 +410,11 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
info.remapValue = remappedValue
} else {
info = invocationParamBuilder.addNextValueParameter(jvmType, false, remappedValue, parameterIndex)
if (kind == ValueKind.NON_INLINEABLE_CALLED_IN_SUSPEND) {
info.functionalArgument = CrossinlineLambdaInSuspendContextAsNoInline
info.functionalArgument = when (kind) {
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND ->
NonInlineableArgumentForInlineableParameterCalledInSuspend(kotlinType?.isSuspendFunctionTypeOrSubtype == true)
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER -> NonInlineableArgumentForInlineableSuspendParameter
else -> null
}
}
@@ -804,15 +808,18 @@ class PsiInlineCodegen(
}
} else {
val value = codegen.gen(argumentExpression)
putValueIfNeeded(
parameterType,
value,
if (isCallSiteIsSuspend(valueParameterDescriptor)) ValueKind.NON_INLINEABLE_CALLED_IN_SUSPEND else ValueKind.GENERAL,
parameterIndex
)
val kind = when {
isCallSiteIsSuspend(valueParameterDescriptor) -> ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND
isInlineSuspendParameter(valueParameterDescriptor) -> ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER
else -> ValueKind.GENERAL
}
putValueIfNeeded(parameterType, value, kind, parameterIndex)
}
}
private fun isInlineSuspendParameter(descriptor: ValueParameterDescriptor): Boolean =
functionDescriptor.isInline && !descriptor.isNoinline && descriptor.type.isSuspendFunctionTypeOrSubtype
private fun isCallSiteIsSuspend(descriptor: ValueParameterDescriptor): Boolean =
state.bindingContext[CodegenBinding.CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA, descriptor] == true
@@ -79,7 +79,8 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu
}
}
object CrossinlineLambdaInSuspendContextAsNoInline : FunctionalArgument
class NonInlineableArgumentForInlineableParameterCalledInSuspend(val isSuspend: Boolean) : FunctionalArgument
object NonInlineableArgumentForInlineableSuspendParameter : FunctionalArgument
class DefaultLambda(
override val lambdaClassType: Type,
@@ -9,16 +9,14 @@ import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
import org.jetbrains.kotlin.codegen.inline.coroutines.*
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.common.ControlFlowGraph
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.common.*
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
@@ -220,6 +218,9 @@ class MethodInliner(
val info = invokeCall.functionalArgument
if (info !is LambdaInfo) {
if (info == NonInlineableArgumentForInlineableSuspendParameter) {
super.visitMethodInsn(Opcodes.INVOKESTATIC, NOINLINE_CALL_MARKER, NOINLINE_CALL_MARKER, "()V", false)
}
//noninlinable lambda
super.visitMethodInsn(opcode, owner, name, desc, itf)
return
@@ -366,6 +367,8 @@ class MethodInliner(
ReifiedTypeInliner.isNeedClassReificationMarker(MethodInsnNode(opcode, owner, name, desc, false))
) {
//we shouldn't process here content of inlining lambda it should be reified at external level except default lambdas
} else if (owner == NOINLINE_CALL_MARKER && name == NOINLINE_CALL_MARKER) {
// do not generate multiple markers on single invoke
} else {
super.visitMethodInsn(opcode, owner, name, desc, itf)
}
@@ -386,7 +389,21 @@ class MethodInliner(
node.accept(lambdaInliner)
return resultNode
return surroundInvokesWithSuspendMarkersIfNeeded(resultNode)
}
private fun surroundInvokesWithSuspendMarkersIfNeeded(node: MethodNode): MethodNode {
val markers = node.instructions.asSequence().filter { it.isNoinlineCallMarker() }.toList()
if (markers.isEmpty()) return node
val invokes = markers.map { it.next as MethodInsnNode }
node.instructions.removeAll(markers)
val sourceFrames = MethodTransformer.analyze(inlineCallSiteInfo.ownerClassName, node, SourceInterpreter())
val toSurround = invokes.mapNotNull { insn ->
findReceiverOfInvoke(sourceFrames[node.instructions.indexOf(insn)], insn)?.let { insn to it }
}
surroundInvokesWithSuspendMarkers(node, toSurround)
return node
}
private fun isDefaultLambdaWithReification(lambdaInfo: LambdaInfo) =
@@ -7,27 +7,34 @@ package org.jetbrains.kotlin.codegen.inline.coroutines
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.coroutines.CoroutineTransformerMethodVisitor
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
import org.jetbrains.kotlin.codegen.coroutines.*
import org.jetbrains.kotlin.codegen.coroutines.getLastParameterIndex
import org.jetbrains.kotlin.codegen.coroutines.isResumeImplMethodName
import org.jetbrains.kotlin.codegen.coroutines.replaceFakeContinuationsWithRealOnes
import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.findPreviousOrNull
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
const val NOINLINE_CALL_MARKER = "NOINLINE_CALL_MARKER"
class CoroutineTransformer(
private val inliningContext: InliningContext,
private val classBuilder: ClassBuilder,
private val methods: List<MethodNode>,
private val superClassName: String
private val superClassName: String,
private val capturedParams: List<CapturedParamInfo>
) {
private val state = inliningContext.state
@@ -94,22 +101,18 @@ class CoroutineTransformer(
ArrayUtil.toStringArray(node.exceptions)
)
) {
CoroutineTransformerMethodVisitor(
classBuilder.newMethod(
JvmDeclarationOrigin.NO_ORIGIN,
node.access,
node.name,
node.desc,
node.signature,
ArrayUtil.toStringArray(node.exceptions)
), node.access, node.name, node.desc, null, null,
obtainClassBuilderForCoroutineState = { classBuilder },
element = element,
diagnostics = state.diagnostics,
languageVersionSettings = state.languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classBuilder.thisName,
isForNamedFunction = false
surroundNoinlineCallsWithMarkersIfNeeded(
node,
CoroutineTransformerMethodVisitor(
createNewMethodFrom(node), node.access, node.name, node.desc, null, null,
obtainClassBuilderForCoroutineState = { classBuilder },
element = element,
diagnostics = state.diagnostics,
languageVersionSettings = state.languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classBuilder.thisName,
isForNamedFunction = false
)
)
}
}
@@ -123,24 +126,48 @@ class CoroutineTransformer(
ArrayUtil.toStringArray(node.exceptions)
)
) {
CoroutineTransformerMethodVisitor(
classBuilder.newMethod(
JvmDeclarationOrigin.NO_ORIGIN, node.access, node.name, node.desc, node.signature,
ArrayUtil.toStringArray(node.exceptions)
), node.access, node.name, node.desc, null, null,
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
element = element,
diagnostics = state.diagnostics,
languageVersionSettings = state.languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classBuilder.thisName,
isForNamedFunction = true,
needDispatchReceiver = true,
internalNameForDispatchReceiver = classBuilder.thisName
surroundNoinlineCallsWithMarkersIfNeeded(
node,
CoroutineTransformerMethodVisitor(
createNewMethodFrom(node), node.access, node.name, node.desc, null, null,
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
element = element,
diagnostics = state.diagnostics,
languageVersionSettings = state.languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classBuilder.thisName,
isForNamedFunction = true,
needDispatchReceiver = true,
internalNameForDispatchReceiver = classBuilder.thisName
)
)
}
}
private fun surroundNoinlineCallsWithMarkersIfNeeded(node: MethodNode, delegate: MethodVisitor): MethodVisitor =
if (capturedParams.any { (it.functionalArgument as? NonInlineableArgumentForInlineableParameterCalledInSuspend)?.isSuspend == true })
SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor(
delegate,
node.access,
node.name,
node.desc,
classBuilder.thisName,
capturedParams
)
else
delegate
private fun createNewMethodFrom(node: MethodNode): MethodVisitor {
return classBuilder.newMethod(
JvmDeclarationOrigin.NO_ORIGIN,
node.access,
node.name,
node.desc,
node.signature,
ArrayUtil.toStringArray(node.exceptions)
)
}
fun replaceFakesWithReals(node: MethodNode) {
findFakeContinuationConstructorClassName(node)?.let(::unregisterClassBuilder)?.let(ClassBuilder::done)
replaceFakeContinuationsWithRealOnes(
@@ -164,4 +191,68 @@ class CoroutineTransformer(
return (new as TypeInsnNode).desc
}
}
}
}
private class SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor(
delegate: MethodVisitor,
access: Int,
name: String,
desc: String,
val thisName: String,
val capturedParams: List<CapturedParamInfo>
) : TransformationMethodVisitor(delegate, access, name, desc, null, null) {
override fun performTransformations(methodNode: MethodNode) {
fun AbstractInsnNode.index() = methodNode.instructions.indexOf(this)
val sourceFrames = MethodTransformer.analyze(thisName, methodNode, SourceInterpreter())
val noinlineInvokes = arrayListOf<Pair<AbstractInsnNode, AbstractInsnNode>>()
for (insn in methodNode.instructions.asSequence()) {
if (insn.opcode != Opcodes.INVOKEINTERFACE) continue
insn as MethodInsnNode
if (!isInvokeOnLambda(insn.owner, insn.name)) continue
val frame = sourceFrames[insn.index()]
val receiver = findReceiverOfInvoke(frame, insn).takeIf { it?.isNoinlineSuspendLambda(insn) == true } as? FieldInsnNode ?: continue
val aload = receiver.findPreviousOrNull { it.opcode != Opcodes.GETFIELD } ?: error("GETFIELD cannot be the first instruction")
assert(aload.opcode == Opcodes.ALOAD) { "Before GETFIELD there shall be ALOAD" }
noinlineInvokes.add(insn to aload)
}
surroundInvokesWithSuspendMarkers(methodNode, noinlineInvokes)
}
private fun AbstractInsnNode.isNoinlineSuspendLambda(invoke: MethodInsnNode): Boolean {
if (opcode != Opcodes.GETFIELD) return false
this as FieldInsnNode
if (owner != thisName || desc != "L${invoke.owner};") return false
val functionalArgument = capturedParams.find { it.newFieldName == name }?.functionalArgument ?: return false
return functionalArgument is NonInlineableArgumentForInlineableParameterCalledInSuspend && functionalArgument.isSuspend
}
}
fun surroundInvokesWithSuspendMarkers(
methodNode: MethodNode,
noinlineInvokes: List<Pair<AbstractInsnNode, AbstractInsnNode>>
) {
for ((invoke, aload) in noinlineInvokes) {
// Generate inline markers for stack transformation. It is required for local variables spilling.
methodNode.instructions.insertBefore(aload, withInstructionAdapter {
addInlineMarker(this, isStartNotEnd = true)
})
methodNode.instructions.insertBefore(invoke, withInstructionAdapter {
addSuspendMarker(this, isStartNotEnd = true)
})
methodNode.instructions.insert(invoke, withInstructionAdapter {
addSuspendMarker(this, isStartNotEnd = false)
addInlineMarker(this, isStartNotEnd = false)
})
}
}
// TODO: What to do if suddenly there are not exactly one receiver?
fun findReceiverOfInvoke(frame: Frame<SourceValue>, insn: MethodInsnNode): AbstractInsnNode? =
frame.getStack(frame.stackSize - insn.owner.removePrefix(NUMBERED_FUNCTION_PREFIX).toInt() - 1)?.insns?.singleOrNull()
fun AbstractInsnNode.isNoinlineCallMarker(): Boolean =
opcode == Opcodes.INVOKESTATIC && cast<MethodInsnNode>().let { it.owner == NOINLINE_CALL_MARKER && it.name == NOINLINE_CALL_MARKER }
@@ -0,0 +1,150 @@
// IGNORE_BACKEND: JVM_IR
// COMMON_COROUTINES_TEST
// WITH_RUNTIME
// WITH_COROUTINES
// NO_CHECK_LAMBDA_INLINING
// CHECK_STATE_MACHINE
// FILE: inline.kt
import helpers.*
interface SuspendRunnable {
suspend fun run()
}
inline fun inlineMe1(crossinline c: suspend () -> Unit) =
object : SuspendRunnable {
override suspend fun run() {
c()
c()
}
}
inline fun inlineMe2(crossinline c: suspend () -> Unit) = suspend {
c()
c()
}
inline suspend fun inlineMe3(crossinline c: suspend () -> Unit) {
c()
c()
}
inline suspend fun inlineMe4(c: suspend () -> Unit) {
c()
c()
}
inline fun inlineMe5(noinline c: suspend () -> Unit) =
object : SuspendRunnable {
override suspend fun run() {
c()
c()
}
}
inline fun inlineMe6(noinline c: suspend () -> Unit) = suspend {
c()
c()
}
inline suspend fun inlineMe7(noinline c: suspend () -> Unit) {
c()
c()
}
inline fun inlineMe11(crossinline c: suspend () -> Unit) = inlineMe1(c)
inline fun inlineMe12(crossinline c: suspend () -> Unit) = inlineMe2(c)
inline suspend fun inlineMe13(crossinline c: suspend () -> Unit) = inlineMe3(c)
inline suspend fun inlineMe14(crossinline c: suspend () -> Unit) = inlineMe4(c)
// FILE: box.kt
// COMMON_COROUTINES_TEST
import helpers.*
import COROUTINES_PACKAGE.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(CheckStateMachineContinuation)
}
fun box(): String {
val lambda = suspend {
StateMachineChecker.suspendHere()
StateMachineChecker.suspendHere()
}
builder {
val r = inlineMe1(lambda)
r.run()
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
inlineMe2(lambda)()
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
inlineMe3(lambda)
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
inlineMe4(lambda)
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
val r = inlineMe5(lambda)
r.run()
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
inlineMe6(lambda)()
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
inlineMe7(lambda)
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
val r = inlineMe11 {
StateMachineChecker.suspendHere()
StateMachineChecker.suspendHere()
}
r.run()
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
inlineMe12 {
StateMachineChecker.suspendHere()
StateMachineChecker.suspendHere()
}()
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
inlineMe13 {
StateMachineChecker.suspendHere()
StateMachineChecker.suspendHere()
}
}
StateMachineChecker.check(numberOfSuspensions = 4)
StateMachineChecker.reset()
builder {
inlineMe14 {
StateMachineChecker.suspendHere()
StateMachineChecker.suspendHere()
}
}
StateMachineChecker.check(numberOfSuspensions = 4)
return "OK"
}
@@ -3936,6 +3936,16 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines");
}
@TestMetadata("passLambda.kt")
public void testPassLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passLambda.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("passLambda.kt")
public void testPassLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passLambda.kt", "kotlin.coroutines");
}
@TestMetadata("passParameterLambda.kt")
public void testPassParameterLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines.experimental");
@@ -3936,6 +3936,16 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines");
}
@TestMetadata("passLambda.kt")
public void testPassLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passLambda.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("passLambda.kt")
public void testPassLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passLambda.kt", "kotlin.coroutines");
}
@TestMetadata("passParameterLambda.kt")
public void testPassParameterLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines.experimental");
@@ -3936,6 +3936,16 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines");
}
@TestMetadata("passLambda.kt")
public void testPassLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passLambda.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("passLambda.kt")
public void testPassLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passLambda.kt", "kotlin.coroutines");
}
@TestMetadata("passParameterLambda.kt")
public void testPassParameterLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines.experimental");
@@ -339,6 +339,11 @@ public class IrInlineSuspendTestsGenerated extends AbstractIrInlineSuspendTests
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines");
}
@TestMetadata("passLambda.kt")
public void testPassLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passLambda.kt", "kotlin.coroutines");
}
@TestMetadata("passParameterLambda.kt")
public void testPassParameterLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines");
@@ -549,6 +549,16 @@ public class InlineSuspendTestsGenerated extends AbstractInlineSuspendTests {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines");
}
@TestMetadata("passLambda.kt")
public void testPassLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passLambda.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("passLambda.kt")
public void testPassLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passLambda.kt", "kotlin.coroutines");
}
@TestMetadata("passParameterLambda.kt")
public void testPassParameterLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines.experimental");